From cvs at cvs.gnupg.org Sun Jul 1 20:07:30 2018 From: cvs at cvs.gnupg.org (by Ben McGinnes) Date: Sun, 01 Jul 2018 20:07:30 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-75-g789ea1b Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 789ea1b019885d5d1db1662e3cd4fda33636e30c (commit) from 35e29e139534ed217340879732a7adfdbd57c91d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 789ea1b019885d5d1db1662e3cd4fda33636e30c Author: Ben McGinnes Date: Mon Jul 2 03:55:19 2018 +1000 python bindings: gpg.core * Changed id/else statements to a more pythonic form from scheme masquerading as python - sorry Justus, it had to go ;). * With the added bonus of enabling PEP8 compliance in those sections. * Fixed remaining PEP8 compliance issues with the exception of the imports at the beginning of the file (changing those will break the entire module, so we'll cope with it as it is). diff --git a/lang/python/src/core.py b/lang/python/src/core.py index 7003b25..ff68bad 100644 --- a/lang/python/src/core.py +++ b/lang/python/src/core.py @@ -762,6 +762,41 @@ class Context(GpgmeWrapper): GPGMEError -- as signaled by the underlying library """ + if sign is True: + _sign = constants.create.SIGN + else: + _sign = 0 + + if encrypt is True: + _encrypt = constants.create.ENCR + else: + _encrypt = 0 + + if certify is True: + _certify = constants.create.CERT + else: + _certify = 0 + + if authenticate is True: + _authenticate = constants.create.AUTH + else: + _authenticate = 0 + + if passphrase is None: + _nopasswd = constants.create.NOPASSWD + else: + _nopasswd = 0 + + if expires is True: + _expires = 0 + else: + _expires = constants.create.NOEXPIRE + + if force is True: + _force = constants.create.FORCE + else: + _force = 0 + if util.is_a_string(passphrase): old_pinentry_mode = self.pinentry_mode old_passphrase_cb = getattr(self, '_passphrase_cb', None) @@ -772,17 +807,10 @@ class Context(GpgmeWrapper): self.set_passphrase_cb(passphrase_cb) try: - self.op_createkey(userid, algorithm, - 0, # reserved - expires_in, - None, # extrakey - ((constants.create.SIGN if sign else 0) - | (constants.create.ENCR if encrypt else 0) - | (constants.create.CERT if certify else 0) - | (constants.create.AUTH if authenticate else 0) - | (constants.create.NOPASSWD if passphrase is None else 0) - | (0 if expires else constants.create.NOEXPIRE) - | (constants.create.FORCE if force else 0))) + self.op_createkey(userid, algorithm, 0, # reserved + expires_in, None, # extrakey + _sign, _encrypt, _certify, _authenticate, + _nopasswd, _expires, _force) finally: if util.is_a_string(passphrase): self.pinentry_mode = old_pinentry_mode @@ -839,6 +867,36 @@ class Context(GpgmeWrapper): GPGMEError -- as signaled by the underlying library """ + if sign is True: + _sign = constants.create.SIGN + else: + _sign = 0 + + if encrypt is True: + _encrypt = constants.create.ENCR + else: + _encrypt = 0 + + if authenticate is True: + _authenticate = constants.create.AUTH + else: + _authenticate = 0 + + if passphrase is None: + _nopasswd = constants.create.NOPASSWD + else: + _nopasswd = 0 + + if expires is True: + _expires = 0 + else: + _expires = constants.create.NOEXPIRE + + if force is True: + _force = constants.create.FORCE + else: + _force = 0 + if util.is_a_string(passphrase): old_pinentry_mode = self.pinentry_mode old_passphrase_cb = getattr(self, '_passphrase_cb', None) @@ -849,15 +907,9 @@ class Context(GpgmeWrapper): self.set_passphrase_cb(passphrase_cb) try: - self.op_createsubkey(key, algorithm, - 0, # reserved - expires_in, - ((constants.create.SIGN if sign else 0) - | (constants.create.ENCR if encrypt else 0) - | (constants.create.AUTH if authenticate else 0) - | (constants.create.NOPASSWD - if passphrase is None else 0) - | (0 if expires else constants.create.NOEXPIRE))) + self.op_createsubkey(key, algorithm, 0, # reserved + expires_in, _sign, _encrypt, _authenticate, + _nopasswd, _expires, _force) finally: if util.is_a_string(passphrase): self.pinentry_mode = old_pinentry_mode @@ -1079,13 +1131,13 @@ class Context(GpgmeWrapper): # $ grep '^gpgme_error_t ' obj/lang/python/python3.5-gpg/gpgme.h \ # | grep -v _op_ | awk "/\(gpgme_ctx/ { printf (\"'%s',\\n\", \$2) } " return ((name.startswith('gpgme_op_') and not - name.endswith('_result')) or name in {'gpgme_new', - 'gpgme_set_ctx_flag', 'gpgme_set_protocol', - 'gpgme_set_sub_protocol', 'gpgme_set_keylist_mode', - 'gpgme_set_pinentry_mode', 'gpgme_set_locale', - 'gpgme_ctx_set_engine_info', 'gpgme_signers_add', - 'gpgme_sig_notation_add', 'gpgme_set_sender', 'gpgme_cancel', - 'gpgme_cancel_async', 'gpgme_get_key'}) + name.endswith('_result')) or name in + {'gpgme_new', 'gpgme_set_ctx_flag', 'gpgme_set_protocol', + 'gpgme_set_sub_protocol', 'gpgme_set_keylist_mode', + 'gpgme_set_pinentry_mode', 'gpgme_set_locale', + 'gpgme_ctx_set_engine_info', 'gpgme_signers_add', + 'gpgme_sig_notation_add', 'gpgme_set_sender', + 'gpgme_cancel', 'gpgme_cancel_async', 'gpgme_get_key'}) _boolean_properties = {'armor', 'textmode', 'offline'} ----------------------------------------------------------------------- Summary of changes: lang/python/src/core.py | 106 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 79 insertions(+), 27 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Sun Jul 1 21:07:15 2018 From: cvs at cvs.gnupg.org (by Ben McGinnes) Date: Sun, 01 Jul 2018 21:07:15 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-76-g5bca499 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 5bca49975063f788b2499342d5a565faf54511db (commit) from 789ea1b019885d5d1db1662e3cd4fda33636e30c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 5bca49975063f788b2499342d5a565faf54511db Author: Ben McGinnes Date: Mon Jul 2 05:05:09 2018 +1000 python bindings: scheming serpents * Apparently I am wrong and Scheme is the new Python after all. * Non-import related PEP8 compliance must wait for another day, though the other PEP8 fixes remain. diff --git a/lang/python/src/core.py b/lang/python/src/core.py index ff68bad..276d2b5 100644 --- a/lang/python/src/core.py +++ b/lang/python/src/core.py @@ -762,41 +762,6 @@ class Context(GpgmeWrapper): GPGMEError -- as signaled by the underlying library """ - if sign is True: - _sign = constants.create.SIGN - else: - _sign = 0 - - if encrypt is True: - _encrypt = constants.create.ENCR - else: - _encrypt = 0 - - if certify is True: - _certify = constants.create.CERT - else: - _certify = 0 - - if authenticate is True: - _authenticate = constants.create.AUTH - else: - _authenticate = 0 - - if passphrase is None: - _nopasswd = constants.create.NOPASSWD - else: - _nopasswd = 0 - - if expires is True: - _expires = 0 - else: - _expires = constants.create.NOEXPIRE - - if force is True: - _force = constants.create.FORCE - else: - _force = 0 - if util.is_a_string(passphrase): old_pinentry_mode = self.pinentry_mode old_passphrase_cb = getattr(self, '_passphrase_cb', None) @@ -809,8 +774,14 @@ class Context(GpgmeWrapper): try: self.op_createkey(userid, algorithm, 0, # reserved expires_in, None, # extrakey - _sign, _encrypt, _certify, _authenticate, - _nopasswd, _expires, _force) + ((constants.create.SIGN if sign else 0) + | (constants.create.ENCR if encrypt else 0) + | (constants.create.CERT if certify else 0) + | (constants.create.AUTH if authenticate else 0) + | (constants.create.NOPASSWD + if passphrase is None else 0) + | (0 if expires else constants.create.NOEXPIRE) + | (constants.create.FORCE if force else 0))) finally: if util.is_a_string(passphrase): self.pinentry_mode = old_pinentry_mode @@ -867,36 +838,6 @@ class Context(GpgmeWrapper): GPGMEError -- as signaled by the underlying library """ - if sign is True: - _sign = constants.create.SIGN - else: - _sign = 0 - - if encrypt is True: - _encrypt = constants.create.ENCR - else: - _encrypt = 0 - - if authenticate is True: - _authenticate = constants.create.AUTH - else: - _authenticate = 0 - - if passphrase is None: - _nopasswd = constants.create.NOPASSWD - else: - _nopasswd = 0 - - if expires is True: - _expires = 0 - else: - _expires = constants.create.NOEXPIRE - - if force is True: - _force = constants.create.FORCE - else: - _force = 0 - if util.is_a_string(passphrase): old_pinentry_mode = self.pinentry_mode old_passphrase_cb = getattr(self, '_passphrase_cb', None) @@ -908,8 +849,15 @@ class Context(GpgmeWrapper): try: self.op_createsubkey(key, algorithm, 0, # reserved - expires_in, _sign, _encrypt, _authenticate, - _nopasswd, _expires, _force) + expires_in, + ((constants.create.SIGN if sign else 0) + | (constants.create.ENCR if encrypt else 0) + | (constants.create.AUTH + if authenticate else 0) + | (constants.create.NOPASSWD + if passphrase is None else 0) + | (0 if expires + else constants.create.NOEXPIRE))) finally: if util.is_a_string(passphrase): self.pinentry_mode = old_pinentry_mode ----------------------------------------------------------------------- Summary of changes: lang/python/src/core.py | 86 ++++++++++--------------------------------------- 1 file changed, 17 insertions(+), 69 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 2 03:47:06 2018 From: cvs at cvs.gnupg.org (by NIIBE Yutaka) Date: Mon, 02 Jul 2018 03:47:06 +0200 Subject: [git] GnuPG - branch, master, updated. gnupg-2.2.7-163-g1aacd12 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 1aacd12471935a354cfd85ee1805edc7eb16e6c5 (commit) from 592deeddb9bf4ae9b3e236b439e2f39644eb6d46 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 1aacd12471935a354cfd85ee1805edc7eb16e6c5 Author: NIIBE Yutaka Date: Mon Jul 2 10:37:49 2018 +0900 libdns: For SOCKS connection, just fails. * dirmngr/dns.c (dns_res_exec): If it's DNS_SO_SOCKS_CONN, don't iterate to other server, but return the error immediately. -- In the function libdns_switch_port_p in dns-stuff.c, this patch allows to fallback using TOR_PORT2 correctly. Fixes-commit: bcdbf8b8ebe9d61160e0b007dabe1b6462ffbc93 Signed-off-by: NIIBE Yutaka diff --git a/dirmngr/dns.c b/dirmngr/dns.c index f82ed26..77f83f4 100644 --- a/dirmngr/dns.c +++ b/dirmngr/dns.c @@ -8846,7 +8846,7 @@ exec: dgoto(R->sp, DNS_R_FOREACH_A); error = dns_so_check(&R->so); - if (error == ECONNREFUSED) + if (R->so.state != DNS_SO_SOCKS_CONN && error == ECONNREFUSED) dgoto(R->sp, DNS_R_FOREACH_A); else if (error) goto error; ----------------------------------------------------------------------- Summary of changes: dirmngr/dns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 2 03:48:55 2018 From: cvs at cvs.gnupg.org (by NIIBE Yutaka) Date: Mon, 02 Jul 2018 03:48:55 +0200 Subject: [git] GnuPG - branch, STABLE-BRANCH-2-2, updated. gnupg-2.2.8-13-gcca92ca Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, STABLE-BRANCH-2-2 has been updated via cca92ca5348999a3564dd54d7b0a103cc9e7640c (commit) from 72a35ffee022f1bf180d02250c5be6a4edb599e7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit cca92ca5348999a3564dd54d7b0a103cc9e7640c Author: NIIBE Yutaka Date: Mon Jul 2 10:37:49 2018 +0900 libdns: For SOCKS connection, just fails. * dirmngr/dns.c (dns_res_exec): If it's DNS_SO_SOCKS_CONN, don't iterate to other server, but return the error immediately. -- Cherry picked from master commit: 1aacd12471935a354cfd85ee1805edc7eb16e6c5 In the function libdns_switch_port_p in dns-stuff.c, this patch allows to fallback using TOR_PORT2 correctly. Fixes-commit: bcdbf8b8ebe9d61160e0b007dabe1b6462ffbc93 Signed-off-by: NIIBE Yutaka diff --git a/dirmngr/dns.c b/dirmngr/dns.c index f82ed26..77f83f4 100644 --- a/dirmngr/dns.c +++ b/dirmngr/dns.c @@ -8846,7 +8846,7 @@ exec: dgoto(R->sp, DNS_R_FOREACH_A); error = dns_so_check(&R->so); - if (error == ECONNREFUSED) + if (R->so.state != DNS_SO_SOCKS_CONN && error == ECONNREFUSED) dgoto(R->sp, DNS_R_FOREACH_A); else if (error) goto error; ----------------------------------------------------------------------- Summary of changes: dirmngr/dns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 2 20:34:54 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Mon, 02 Jul 2018 20:34:54 +0200 Subject: [git] GnuPG - branch, master, updated. gnupg-2.2.7-165-g58baf40 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 58baf40af641f8cbf597e508a292e85ae94688f1 (commit) via 3978df943dc7a4781a23382be2d3b4a96a04f71f (commit) from 1aacd12471935a354cfd85ee1805edc7eb16e6c5 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 58baf40af641f8cbf597e508a292e85ae94688f1 Author: Werner Koch Date: Mon Jul 2 20:24:10 2018 +0200 common: New function percent_data_escape. * common/percent.c (percent_data_escape): New. * common/t-percent.c (test_percent_data_escape): New. Signed-off-by: Werner Koch diff --git a/common/percent.c b/common/percent.c index 569c5fd..eeb026f 100644 --- a/common/percent.c +++ b/common/percent.c @@ -87,6 +87,50 @@ percent_plus_escape (const char *string) } +/* Create a newly alloced string from (DATA,DATALEN) with embedded + * Nuls quoted as %00. The standard percent unescaping can be + * used to reverse this encoding. */ +char * +percent_data_escape (const void *data, size_t datalen) +{ + char *buffer, *p; + const char *s; + size_t n, length; + + for (length=1, s=data, n=datalen; n; s++, n--) + { + if (!*s || *s == '%') + length += 3; + else + length++; + } + + buffer = p = xtrymalloc (length); + if (!buffer) + return NULL; + + for (s=data, n=datalen; n; s++, n--) + { + if (!*s) + { + memcpy (p, "%00", 3); + p += 3; + } + else if (*s == '%') + { + memcpy (p, "%25", 3); + p += 3; + } + else + *p++ = *s; + } + *p = 0; + + return buffer; + +} + + /* Do the percent and plus/space unescaping from STRING to BUFFER and return the length of the valid buffer. Plus unescaping is only done if WITHPLUS is true. An escaped Nul character will be diff --git a/common/t-percent.c b/common/t-percent.c index 145a89b..94ece92 100644 --- a/common/t-percent.c +++ b/common/t-percent.c @@ -99,6 +99,55 @@ test_percent_plus_escape (void) } +static void +test_percent_data_escape (void) +{ + static struct { + const char *data; + size_t datalen; + const char *expect; + } tbl[] = { + { + "", 0, + "" + }, { + "a", 1, + "a", + }, { + "%22", 3, + "%2522" + }, { + "%%", 3, + "%25%25%00" + }, { + "\n \0BC\t", 6, + "\n %00BC\t" + }, { NULL, 0, NULL } + }; + char *buf; + int i; + size_t len; + + for (i=0; tbl[i].data; i++) + { + buf = percent_data_escape (tbl[i].data, tbl[i].datalen); + if (!buf) + { + fprintf (stderr, "out of core: %s\n", strerror (errno)); + exit (2); + } + if (strcmp (buf, tbl[i].expect)) + fail (i); + len = percent_plus_unescape_inplace (buf, 0); + if (len != tbl[i].datalen) + fail (i); + else if (memcmp (buf, tbl[i].data, tbl[i].datalen)) + fail (i); + xfree (buf); + } +} + + int main (int argc, char **argv) @@ -109,6 +158,6 @@ main (int argc, char **argv) /* FIXME: We escape_unescape is not tested - only percent_plus_unescape. */ test_percent_plus_escape (); - + test_percent_data_escape (); return 0; } diff --git a/common/util.h b/common/util.h index 123d880..682415d 100644 --- a/common/util.h +++ b/common/util.h @@ -201,6 +201,7 @@ char *hex2str_alloc (const char *hexstring, size_t *r_count); /*-- percent.c --*/ char *percent_plus_escape (const char *string); +char *percent_data_escape (const void *data, size_t datalen); char *percent_plus_unescape (const char *string, int nulrepl); char *percent_unescape (const char *string, int nulrepl); commit 3978df943dc7a4781a23382be2d3b4a96a04f71f Author: Werner Koch Date: Mon Jul 2 20:22:42 2018 +0200 agent: Fix segv running in --server mode * agent/command.c (start_command_handler): Do not write to CLIENT_CREDS after an error. -- assuan_get_peercred is special insofar that it returns a pointer into CTX. Writing data via this pointer should never be done. Fixes-commit: 28aa6890588cc108639951bb4bef03ac17743046 Signed-off-by: Werner Koch diff --git a/agent/command.c b/agent/command.c index 1a08cfc..9bc3b02 100644 --- a/agent/command.c +++ b/agent/command.c @@ -3351,7 +3351,8 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd) for (;;) { - assuan_peercred_t client_creds; + assuan_peercred_t client_creds; /* Note: Points into CTX. */ + pid_t pid; rc = assuan_accept (ctx); if (gpg_err_code (rc) == GPG_ERR_EOF || rc == -1) @@ -3367,17 +3368,21 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd) 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); + + if (listen_fd == GNUPG_INVALID_FD && fd == GNUPG_INVALID_FD) + ; + else + log_info ("Assuan get_peercred failed: %s\n", gpg_strerror (rc)); + 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; + { + pid = client_creds->pid; + ctrl->client_uid = client_creds->uid; + } + ctrl->client_pid = (pid == ASSUAN_INVALID_PID)? 0 : (unsigned long)pid; + ctrl->server_local->connect_from_self = (pid == getpid ()); rc = assuan_process (ctx); if (rc) ----------------------------------------------------------------------- Summary of changes: agent/command.c | 23 ++++++++++++++--------- common/percent.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ common/t-percent.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- common/util.h | 1 + 4 files changed, 109 insertions(+), 10 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 2 21:44:37 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Mon, 02 Jul 2018 21:44:37 +0200 Subject: [git] GnuPG - branch, master, updated. gnupg-2.2.7-166-g8a915cd Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 8a915cd9faf052b4faa3c415f2ac5aa8d6ea1efe (commit) from 58baf40af641f8cbf597e508a292e85ae94688f1 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 8a915cd9faf052b4faa3c415f2ac5aa8d6ea1efe Author: Werner Koch Date: Mon Jul 2 21:24:15 2018 +0200 agent: New commands PUT_SECRET and GET_SECRET. * agent/agent.h (CACHE_MODE_DATA): New const. * agent/cache.c (DEF_CACHE_TTL_DATA): new. (housekeeping): Tweak for CACHE_MODE_DATA. (cache_mode_equal): Ditto. (agent_get_cache): Ditto. (agent_put_cache): Implement CACHE_MODE_DATA. * agent/command.c (MAXLEN_PUT_SECRET): New. (parse_ttl): New. (cmd_get_secret): New. (cmd_put_secret): New. (register_commands): Register new commands. -- These commands allow to store secrets in memory for the lifetime of the gpg-agent process. Signed-off-by: Werner Koch diff --git a/agent/agent.h b/agent/agent.h index 9fdbc76..9baf596 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -304,11 +304,12 @@ enum typedef enum { CACHE_MODE_IGNORE = 0, /* Special mode to bypass the cache. */ - CACHE_MODE_ANY, /* Any mode except ignore matches. */ + CACHE_MODE_ANY, /* Any mode except ignore and data matches. */ CACHE_MODE_NORMAL, /* Normal cache (gpg-agent). */ CACHE_MODE_USER, /* GET_PASSPHRASE related cache. */ CACHE_MODE_SSH, /* SSH related cache. */ - CACHE_MODE_NONCE /* This is a non-predictable nonce. */ + CACHE_MODE_NONCE, /* This is a non-predictable nonce. */ + CACHE_MODE_DATA /* Arbitrary data. */ } cache_mode_t; diff --git a/agent/cache.c b/agent/cache.c index 238b6e2..799d595 100644 --- a/agent/cache.c +++ b/agent/cache.c @@ -28,6 +28,10 @@ #include "agent.h" +/* The default TTL for DATA items. This has no configure + * option because it is expected that clients provide a TTL. */ +#define DEF_CACHE_TTL_DATA (10 * 60) /* 10 minutes. */ + /* The size of the encryption key in bytes. */ #define ENCRYPTION_KEYSIZE (128/8) @@ -50,11 +54,12 @@ struct secret_data_s { char data[1]; /* A string. */ }; +/* The cache object. */ typedef struct cache_item_s *ITEM; struct cache_item_s { ITEM next; time_t created; - time_t accessed; + time_t accessed; /* Not updated for CACHE_MODE_DATA */ int ttl; /* max. lifetime given in seconds, -1 one means infinite */ struct secret_data_s *pw; cache_mode_t cache_mode; @@ -211,14 +216,18 @@ housekeeping (void) } } - /* Second, make sure that we also remove them based on the created stamp so - that the user has to enter it from time to time. */ + /* Second, make sure that we also remove them based on the created + * stamp so that the user has to enter it from time to time. We + * don't do this for data items which are used to storage secrets in + * meory and are not user entered passphrases etc. */ for (r=thecache; r; r = r->next) { unsigned long maxttl; switch (r->cache_mode) { + case CACHE_MODE_DATA: + continue; /* No MAX TTL here. */ case CACHE_MODE_SSH: maxttl = opt.max_cache_ttl_ssh; break; default: maxttl = opt.max_cache_ttl; break; } @@ -315,8 +324,11 @@ static int cache_mode_equal (cache_mode_t a, cache_mode_t b) { /* CACHE_MODE_ANY matches any mode other than CACHE_MODE_IGNORE. */ - return ((a == CACHE_MODE_ANY && b != CACHE_MODE_IGNORE) - || (b == CACHE_MODE_ANY && a != CACHE_MODE_IGNORE) || a == b); + return ((a == CACHE_MODE_ANY + && !(b == CACHE_MODE_IGNORE || b == CACHE_MODE_DATA)) + || (b == CACHE_MODE_ANY + && !(a == CACHE_MODE_IGNORE || a == CACHE_MODE_DATA)) + || a == b); } @@ -349,6 +361,7 @@ agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode, switch(cache_mode) { case CACHE_MODE_SSH: ttl = opt.def_cache_ttl_ssh; break; + case CACHE_MODE_DATA: ttl = DEF_CACHE_TTL_DATA; break; default: ttl = opt.def_cache_ttl; break; } } @@ -415,9 +428,7 @@ agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode, } -/* Try to find an item in the cache. Note that we currently don't - make use of CACHE_MODE except for CACHE_MODE_NONCE and - CACHE_MODE_USER. */ +/* Try to find an item in the cache. */ char * agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode) { @@ -458,8 +469,11 @@ agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode) && r->restricted == restricted && !strcmp (r->key, key)) { - /* Note: To avoid races KEY may not be accessed anymore below. */ - r->accessed = gnupg_get_time (); + /* Note: To avoid races KEY may not be accessed anymore + * below. Note also that we don't update the accessed time + * for data items. */ + if (r->cache_mode != CACHE_MODE_DATA) + r->accessed = gnupg_get_time (); if (DBG_CACHE) log_debug ("... hit\n"); if (r->pw->totallen < 32) diff --git a/agent/command.c b/agent/command.c index 9bc3b02..925d1f7 100644 --- a/agent/command.c +++ b/agent/command.c @@ -50,6 +50,8 @@ #define MAXLEN_KEYPARAM 1024 /* Maximum allowed size of key data as used in inquiries (bytes). */ #define MAXLEN_KEYDATA 8192 +/* Maximum length of a secret to store under one key. */ +#define MAXLEN_PUT_SECRET 4096 /* The size of the import/export KEK key (in bytes). */ #define KEYWRAP_KEYSIZE (128/8) @@ -292,6 +294,31 @@ parse_keygrip (assuan_context_t ctx, const char *string, unsigned char *buf) } +/* Parse the TTL from STRING. Leading and trailing spaces are + * skipped. The value is constrained to -1 .. MAXINT. On error 0 is + * returned, else the number of bytes scanned. */ +static size_t +parse_ttl (const char *string, int *r_ttl) +{ + const char *string_orig = string; + long ttl; + char *pend; + + ttl = strtol (string, &pend, 10); + string = pend; + if (string == string_orig || !(spacep (string) || !*string) + || ttl < -1L || (int)ttl != (long)ttl) + { + *r_ttl = 0; + return 0; + } + while (spacep (string) || *string== '\n') + string++; + *r_ttl = (int)ttl; + return string - string_orig; +} + + /* Write an Assuan status line. KEYWORD is the first item on the * status line. The following arguments are all separated by a space * in the output. The last argument must be a NULL. Linefeeds and @@ -2568,6 +2595,187 @@ cmd_keytocard (assuan_context_t ctx, char *line) +static const char hlp_get_secret[] = + "GET_SECRET \n" + "\n" + "Return the secret value stored under KEY\n"; +static gpg_error_t +cmd_get_secret (assuan_context_t ctx, char *line) +{ + ctrl_t ctrl = assuan_get_pointer (ctx); + gpg_error_t err; + char *p, *key; + char *value = NULL; + size_t valuelen; + + /* For now we allow this only for local connections. */ + if (ctrl->restricted) + { + err = gpg_error (GPG_ERR_FORBIDDEN); + goto leave; + } + + line = skip_options (line); + + for (p=line; *p == ' '; p++) + ; + key = p; + p = strchr (key, ' '); + if (p) + { + *p++ = 0; + for (; *p == ' '; p++) + ; + if (*p) + { + err = set_error (GPG_ERR_ASS_PARAMETER, "too many arguments"); + goto leave; + } + } + if (!*key) + { + err = set_error (GPG_ERR_ASS_PARAMETER, "no key given"); + goto leave; + } + + + value = agent_get_cache (ctrl, key, CACHE_MODE_DATA); + if (!value) + { + err = gpg_error (GPG_ERR_NO_DATA); + goto leave; + } + + valuelen = percent_unescape_inplace (value, 0); + err = assuan_send_data (ctx, value, valuelen); + wipememory (value, valuelen); + + leave: + xfree (value); + return leave_cmd (ctx, err); +} + + +static const char hlp_put_secret[] = + "PUT_SECRET [--clear] []\n" + "\n" + "This commands stores a secret under KEY in gpg-agent's in-memory\n" + "cache. The TTL must be explicitly given by TTL and the options\n" + "from the configuration file are not used. The value is either given\n" + "percent-escaped as 3rd argument or if not given inquired by gpg-agent\n" + "using the keyword \"SECRET\".\n" + "The option --clear removes the secret from the cache." + ""; +static gpg_error_t +cmd_put_secret (assuan_context_t ctx, char *line) +{ + ctrl_t ctrl = assuan_get_pointer (ctx); + gpg_error_t err = 0; + int opt_clear; + unsigned char *value = NULL; + size_t valuelen = 0; + size_t n; + char *p, *key, *ttlstr; + unsigned char *valstr; + int ttl; + char *string = NULL; + + /* For now we allow this only for local connections. */ + if (ctrl->restricted) + { + err = gpg_error (GPG_ERR_FORBIDDEN); + goto leave; + } + + opt_clear = has_option (line, "--clear"); + line = skip_options (line); + + for (p=line; *p == ' '; p++) + ; + key = p; + ttlstr = NULL; + valstr = NULL; + p = strchr (key, ' '); + if (p) + { + *p++ = 0; + for (; *p == ' '; p++) + ; + if (*p) + { + ttlstr = p; + p = strchr (ttlstr, ' '); + if (p) + { + *p++ = 0; + for (; *p == ' '; p++) + ; + if (*p) + valstr = p; + } + } + } + if (!*key) + { + err = set_error (GPG_ERR_ASS_PARAMETER, "no key given"); + goto leave; + } + if (!ttlstr || !*ttlstr || !(n = parse_ttl (ttlstr, &ttl))) + { + err = set_error (GPG_ERR_ASS_PARAMETER, "no or invalid TTL given"); + goto leave; + } + if (valstr && opt_clear) + { + err = set_error (GPG_ERR_ASS_PARAMETER, + "value not expected with --clear"); + goto leave; + } + + if (valstr) + { + valuelen = percent_unescape_inplace (valstr, 0); + value = NULL; + } + else /* Inquire the value to store */ + { + err = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%u",MAXLEN_PUT_SECRET); + if (!err) + err = assuan_inquire (ctx, "SECRET", + &value, &valuelen, MAXLEN_PUT_SECRET); + if (err) + goto leave; + } + + /* Our cache expects strings and thus we need to turn the buffer + * into a string. Instead of resorting to base64 encoding we use a + * special percent escaping which only quoted the Nul and the + * percent character. */ + string = percent_data_escape (value? value : valstr, valuelen); + if (!string) + { + err = gpg_error_from_syserror (); + goto leave; + } + err = agent_put_cache (ctrl, key, CACHE_MODE_DATA, string, ttl); + + + leave: + if (string) + { + wipememory (string, strlen (string)); + xfree (string); + } + if (value) + { + wipememory (value, valuelen); + xfree (value); + } + return leave_cmd (ctx, err); +} + + + static const char hlp_getval[] = "GETVAL \n" "\n" @@ -3259,6 +3467,8 @@ register_commands (assuan_context_t ctx) { "IMPORT_KEY", cmd_import_key, hlp_import_key }, { "EXPORT_KEY", cmd_export_key, hlp_export_key }, { "DELETE_KEY", cmd_delete_key, hlp_delete_key }, + { "GET_SECRET", cmd_get_secret, hlp_get_secret }, + { "PUT_SECRET", cmd_put_secret, hlp_put_secret }, { "GETVAL", cmd_getval, hlp_getval }, { "PUTVAL", cmd_putval, hlp_putval }, { "UPDATESTARTUPTTY", cmd_updatestartuptty, hlp_updatestartuptty }, ----------------------------------------------------------------------- Summary of changes: agent/agent.h | 5 +- agent/cache.c | 34 ++++++--- agent/command.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 237 insertions(+), 12 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 3 02:15:56 2018 From: cvs at cvs.gnupg.org (by NIIBE Yutaka) Date: Tue, 03 Jul 2018 02:15:56 +0200 Subject: [git] GnuPG - branch, master, updated. gnupg-2.2.7-167-g996febb Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 996febbab21eb9283b0634e51303a36b318734a6 (commit) from 8a915cd9faf052b4faa3c415f2ac5aa8d6ea1efe (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 996febbab21eb9283b0634e51303a36b318734a6 Author: NIIBE Yutaka Date: Tue Jul 3 09:07:03 2018 +0900 g10: Fix memory leak for PKT_signature. * g10/getkey.c (buf_to_sig): Free by free_seckey_enc. * g10/gpgcompose.c (signature): Likewise. * g10/sign.c (write_signature_packets): Likewise. -- Reported-by: Philippe Antoine GnuPG-bug-id: 4047 Signed-off-by: NIIBE Yutaka diff --git a/g10/getkey.c b/g10/getkey.c index b111376..f0132bb 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -3142,7 +3142,7 @@ buf_to_sig (const byte * buf, size_t len) if (parse_signature (iobuf, PKT_SIGNATURE, len, sig) != 0) { - xfree (sig); + free_seckey_enc (sig); sig = NULL; } diff --git a/g10/gpgcompose.c b/g10/gpgcompose.c index 094bc76..b3f7ecd 100644 --- a/g10/gpgcompose.c +++ b/g10/gpgcompose.c @@ -1835,7 +1835,7 @@ signature (const char *option, int argc, char *argv[], void *cookie) debug ("Wrote signature packet:\n"); dump_component (&pkt); - xfree (sig); + free_seckey_enc (sig); release_kbnode (si.issuer_kb); xfree (si.revocation_key); diff --git a/g10/sign.c b/g10/sign.c index df71ccc..581a08f 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -772,7 +772,7 @@ write_signature_packets (ctrl_t ctrl, gpg_strerror (rc)); } else - xfree (sig); + free_seckey_enc (sig); if (rc) return rc; ----------------------------------------------------------------------- Summary of changes: g10/getkey.c | 2 +- g10/gpgcompose.c | 2 +- g10/sign.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 3 02:22:22 2018 From: cvs at cvs.gnupg.org (by NIIBE Yutaka) Date: Tue, 03 Jul 2018 02:22:22 +0200 Subject: [git] GnuPG - branch, STABLE-BRANCH-2-2, updated. gnupg-2.2.8-14-g2809be1 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, STABLE-BRANCH-2-2 has been updated via 2809be1f97a447171a9e8b40079851740b15341a (commit) from cca92ca5348999a3564dd54d7b0a103cc9e7640c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 2809be1f97a447171a9e8b40079851740b15341a Author: NIIBE Yutaka Date: Tue Jul 3 09:07:03 2018 +0900 g10: Fix memory leak for PKT_signature. * g10/getkey.c (buf_to_sig): Free by free_seckey_enc. * g10/gpgcompose.c (signature): Likewise. * g10/sign.c (write_signature_packets): Likewise. -- Cherry picked from master commit: 996febbab21eb9283b0634e51303a36b318734a6 Reported-by: Philippe Antoine GnuPG-bug-id: 4047 Signed-off-by: NIIBE Yutaka diff --git a/g10/getkey.c b/g10/getkey.c index c77b409..7c407dd 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -3128,7 +3128,7 @@ buf_to_sig (const byte * buf, size_t len) if (parse_signature (iobuf, PKT_SIGNATURE, len, sig) != 0) { - xfree (sig); + free_seckey_enc (sig); sig = NULL; } diff --git a/g10/gpgcompose.c b/g10/gpgcompose.c index 2b42bfb..430538e 100644 --- a/g10/gpgcompose.c +++ b/g10/gpgcompose.c @@ -1835,7 +1835,7 @@ signature (const char *option, int argc, char *argv[], void *cookie) debug ("Wrote signature packet:\n"); dump_component (&pkt); - xfree (sig); + free_seckey_enc (sig); release_kbnode (si.issuer_kb); xfree (si.revocation_key); diff --git a/g10/sign.c b/g10/sign.c index 4cf0cd3..095fa11 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -772,7 +772,7 @@ write_signature_packets (ctrl_t ctrl, gpg_strerror (rc)); } else - xfree (sig); + free_seckey_enc (sig); if (rc) return rc; ----------------------------------------------------------------------- Summary of changes: g10/getkey.c | 2 +- g10/gpgcompose.c | 2 +- g10/sign.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 3 12:33:30 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Tue, 03 Jul 2018 12:33:30 +0200 Subject: [git] GnuPG - branch, STABLE-BRANCH-2-2, updated. gnupg-2.2.8-17-g04fb766 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, STABLE-BRANCH-2-2 has been updated via 04fb76684d8b2c9cda2e5c35bad6edec521cffa5 (commit) via a8e24addcc4e0fdff7d07acdd7e13bf6febf97d2 (commit) via 5c67ee160d4969b1ef94642ac602e1aed4d9a6d7 (commit) from 2809be1f97a447171a9e8b40079851740b15341a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 04fb76684d8b2c9cda2e5c35bad6edec521cffa5 Author: Werner Koch Date: Thu Jun 21 20:28:40 2018 +0200 gpg: Print revocation reason for "rev" records. * g10/main.h: Add prototype. * g10/keylist.c (list_keyblock_print): Print revocation info. (list_keyblock_colon): Ditto. * g10/test-stubs.c (get_revocation_reason): New stub. * g10/gpgv.c (get_revocation_reason): New stub. -- GnuPG-bug-id: 1173 Signed-off-by: Werner Koch (cherry picked from commit 592deeddb9bf4ae9b3e236b439e2f39644eb6d46) diff --git a/g10/gpgv.c b/g10/gpgv.c index c43067d..c142cef 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -772,3 +772,18 @@ tofu_notice_key_changed (ctrl_t ctrl, kbnode_t kb) return 0; } + + +int +get_revocation_reason (PKT_signature *sig, char **r_reason, + char **r_comment, size_t *r_commentlen) +{ + (void)sig; + (void)r_commentlen; + + if (r_reason) + *r_reason = NULL; + if (r_comment) + *r_comment = NULL; + return 0; +} diff --git a/g10/keylist.c b/g10/keylist.c index 199cd13..c9121a1 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -1070,6 +1070,9 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, PKT_signature *sig = node->pkt->pkt.signature; int sigrc; char *sigstr; + char *reason_text = NULL; + char *reason_comment = NULL; + size_t reason_commentlen; if (listctx->check_sigs) { @@ -1106,7 +1109,11 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, if (sig->sig_class == 0x20 || sig->sig_class == 0x28 || sig->sig_class == 0x30) - sigstr = "rev"; + { + sigstr = "rev"; + get_revocation_reason (sig, &reason_text, + &reason_comment, &reason_commentlen); + } else if ((sig->sig_class & ~3) == 0x10) sigstr = "sig"; else if (sig->sig_class == 0x18) @@ -1168,6 +1175,40 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, && (opt.list_options & LIST_SHOW_KEYSERVER_URLS)) show_keyserver_url (sig, 3, 0); + if (reason_text) + { + es_fprintf (es_stdout, " %s%s\n", + _("reason for revocation: "), reason_text); + if (reason_comment) + { + const byte *s, *s_lf; + size_t n, n_lf; + + s = reason_comment; + n = reason_commentlen; + s_lf = NULL; + do + { + /* We don't want any empty lines, so we skip them. */ + for (;n && *s == '\n'; s++, n--) + ; + if (n) + { + s_lf = memchr (s, '\n', n); + n_lf = s_lf? s_lf - s : n; + es_fprintf (es_stdout, " %s", + _("revocation comment: ")); + es_write_sanitized (es_stdout, s, n_lf, NULL, NULL); + es_putc ('\n', es_stdout); + s += n_lf; n -= n_lf; + } + } while (s_lf); + } + } + + xfree (reason_text); + xfree (reason_comment); + /* fixme: check or list other sigs here */ } } @@ -1514,10 +1555,19 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock, char *siguid; size_t siguidlen; char *issuer_fpr = NULL; + char *reason_text = NULL; + char *reason_comment = NULL; + size_t reason_commentlen; + int reason_code; if (sig->sig_class == 0x20 || sig->sig_class == 0x28 || sig->sig_class == 0x30) - sigstr = "rev"; + { + sigstr = "rev"; + reason_code = get_revocation_reason (sig, &reason_text, + &reason_comment, + &reason_commentlen); + } else if ((sig->sig_class & ~3) == 0x10) sigstr = "sig"; else if (sig->sig_class == 0x18) @@ -1611,8 +1661,11 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock, else if (siguid) es_write_sanitized (es_stdout, siguid, siguidlen, ":", NULL); - es_fprintf (es_stdout, ":%02x%c::", sig->sig_class, + es_fprintf (es_stdout, ":%02x%c", sig->sig_class, sig->flags.exportable ? 'x' : 'l'); + if (reason_text) + es_fprintf (es_stdout, ",%02x", reason_code); + es_fputs ("::", es_stdout); if (opt.no_sig_cache && opt.check_sigs && fprokay) { @@ -1622,12 +1675,23 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock, else if ((issuer_fpr = issuer_fpr_string (sig))) es_fputs (issuer_fpr, es_stdout); - es_fprintf (es_stdout, ":::%d:\n", sig->digest_algo); + es_fprintf (es_stdout, ":::%d:", sig->digest_algo); + + if (reason_comment) + { + es_fputs ("::::", es_stdout); + es_write_sanitized (es_stdout, reason_comment, reason_commentlen, + ":", NULL); + es_putc (':', es_stdout); + } + es_putc ('\n', es_stdout); if (opt.show_subpackets) print_subpackets_colon (sig); /* fixme: check or list other sigs here */ + xfree (reason_text); + xfree (reason_comment); xfree (siguid); xfree (issuer_fpr); } diff --git a/g10/main.h b/g10/main.h index af25d55..389a557 100644 --- a/g10/main.h +++ b/g10/main.h @@ -378,6 +378,9 @@ gpg_error_t transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats, int collapse_uids( KBNODE *keyblock ); +int get_revocation_reason (PKT_signature *sig, char **r_reason, + char **r_comment, size_t *r_commentlen); + /*-- export.c --*/ struct export_stats_s; diff --git a/g10/test-stubs.c b/g10/test-stubs.c index e5fd3ae..1e13632 100644 --- a/g10/test-stubs.c +++ b/g10/test-stubs.c @@ -535,3 +535,17 @@ tofu_notice_key_changed (ctrl_t ctrl, kbnode_t kb) return 0; } + +int +get_revocation_reason (PKT_signature *sig, char **r_reason, + char **r_comment, size_t *r_commentlen) +{ + (void)sig; + (void)r_commentlen; + + if (r_reason) + *r_reason = NULL; + if (r_comment) + *r_comment = NULL; + return 0; +} commit a8e24addcc4e0fdff7d07acdd7e13bf6febf97d2 Author: Werner Koch Date: Thu Jun 21 18:32:13 2018 +0200 gpg: Print revocation reason for "rvs" records. * g10/import.c (get_revocation_reason): New. (list_standalone_revocation): Extend function. -- Note that this function extends the "rvs" field signature-class (field 11) with the revocation reason. GPGME does not yet parse this but it can be expected that the comma delimiter does not break other parsers. A new field is added to the "rvs" (and in future also the "rev") record to carry a record specific comment. Hopefully all parsers meanwhile learned the lesson from other new fields and don't bail out on more fields than they know about. This is partial solution to GnuPG-bug-id: 1173 Signed-off-by: Werner Koch (cherry picked from commit b7cd2c2093ae1b47645be50fa1d431a028187cad) diff --git a/doc/DETAILS b/doc/DETAILS index ce666da..dea9d42 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -180,6 +180,9 @@ described here. revocation key is also given here, 'x' and 'l' is used the same way. This field if not used for X.509. + "rev" and "rvs" may be followed by a comma and a 2 digit hexnumber + with the revocation reason. + *** Field 12 - Key capabilities The defined capabilities are: @@ -260,6 +263,12 @@ described here. optionally followed by a space and an URL. This goes along with the previous field. The URL is quoted in C style. +*** Field 21 - Comment + + This is currently only used in "rev" and "rvs" records to carry + the the comment field of the recocation reason. The value is + quoted in C style. + ** Special fields *** PKD - Public key data diff --git a/g10/import.c b/g10/import.c index 0f2ccfd..49381d4 100644 --- a/g10/import.c +++ b/g10/import.c @@ -2614,6 +2614,69 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock, +/* Return the recocation reason from signature SIG. If no revocation + * reason is availabale 0 is returned, in other cases the reason + * (0..255). If R_REASON is not NULL a malloced textual + * representation of the code is stored there. If R_COMMENT is not + * NULL the comment from the reason is stored there and its length at + * R_COMMENTLEN. Note that the value at R_COMMENT is not filtered but + * user supplied data in UTF8; thus it needs to be escaped for display + * purposes. Both return values are either NULL or a malloced + * string/buffer. */ +int +get_revocation_reason (PKT_signature *sig, char **r_reason, + char **r_comment, size_t *r_commentlen) +{ + int reason_seq = 0; + size_t reason_n; + const byte *reason_p; + char reason_code_buf[20]; + const char *reason_text = NULL; + int reason_code = 0; + + if (r_reason) + *r_reason = NULL; + if (r_comment) + *r_comment = NULL; + + /* Skip over empty reason packets. */ + while ((reason_p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REVOC_REASON, + &reason_n, &reason_seq, NULL)) + && !reason_n) + ; + if (reason_p) + { + reason_code = *reason_p; + reason_n--; reason_p++; + switch (reason_code) + { + case 0x00: reason_text = _("No reason specified"); break; + case 0x01: reason_text = _("Key is superseded"); break; + case 0x02: reason_text = _("Key has been compromised"); break; + case 0x03: reason_text = _("Key is no longer used"); break; + case 0x20: reason_text = _("User ID is no longer valid"); break; + default: + snprintf (reason_code_buf, sizeof reason_code_buf, + "code=%02x", reason_code); + reason_text = reason_code_buf; + break; + } + + if (r_reason) + *r_reason = xstrdup (reason_text); + + if (r_comment && reason_n) + { + *r_comment = xmalloc (reason_n); + memcpy (*r_comment, reason_p, reason_n); + *r_commentlen = reason_n; + } + } + + return reason_code; +} + + /* List the recocation signature as a "rvs" record. SIGRC shows the * character from the signature verification or 0 if no public key was * found. */ @@ -2623,6 +2686,10 @@ list_standalone_revocation (ctrl_t ctrl, PKT_signature *sig, int sigrc) char *siguid = NULL; size_t siguidlen = 0; char *issuer_fpr = NULL; + int reason_code = 0; + char *reason_text = NULL; + char *reason_comment = NULL; + size_t reason_commentlen; if (sigrc != '%' && sigrc != '?' && !opt.fast_list_mode) { @@ -2632,6 +2699,9 @@ list_standalone_revocation (ctrl_t ctrl, PKT_signature *sig, int sigrc) sigrc = '?'; } + reason_code = get_revocation_reason (sig, &reason_text, + &reason_comment, &reason_commentlen); + if (opt.with_colons) { es_fputs ("rvs:", es_stdout); @@ -2646,13 +2716,25 @@ list_standalone_revocation (ctrl_t ctrl, PKT_signature *sig, int sigrc) if (siguid) es_write_sanitized (es_stdout, siguid, siguidlen, ":", NULL); - es_fprintf (es_stdout, ":%02x%c::", sig->sig_class, + es_fprintf (es_stdout, ":%02x%c", sig->sig_class, sig->flags.exportable ? 'x' : 'l'); + if (reason_text) + es_fprintf (es_stdout, ",%02x", reason_code); + es_fputs ("::", es_stdout); if ((issuer_fpr = issuer_fpr_string (sig))) es_fputs (issuer_fpr, es_stdout); - es_fprintf (es_stdout, ":::%d:\n", sig->digest_algo); + es_fprintf (es_stdout, ":::%d:", sig->digest_algo); + + if (reason_comment) + { + es_fputs ("::::", es_stdout); + es_write_sanitized (es_stdout, reason_comment, reason_commentlen, + ":", NULL); + es_putc (':', es_stdout); + } + es_putc ('\n', es_stdout); if (opt.show_subpackets) print_subpackets_colon (sig); @@ -2693,10 +2775,43 @@ list_standalone_revocation (ctrl_t ctrl, PKT_signature *sig, int sigrc) if (sig->flags.pref_ks && (opt.list_options & LIST_SHOW_KEYSERVER_URLS)) show_keyserver_url (sig, 3, 0); + + if (reason_text) + { + es_fprintf (es_stdout, " %s%s\n", + _("reason for revocation: "), reason_text); + if (reason_comment) + { + const byte *s, *s_lf; + size_t n, n_lf; + + s = reason_comment; + n = reason_commentlen; + s_lf = NULL; + do + { + /* We don't want any empty lines, so we skip them. */ + for (;n && *s == '\n'; s++, n--) + ; + if (n) + { + s_lf = memchr (s, '\n', n); + n_lf = s_lf? s_lf - s : n; + es_fprintf (es_stdout, " %s", + _("revocation comment: ")); + es_write_sanitized (es_stdout, s, n_lf, NULL, NULL); + es_putc ('\n', es_stdout); + s += n_lf; n -= n_lf; + } + } while (s_lf); + } + } } es_fflush (es_stdout); + xfree (reason_text); + xfree (reason_comment); xfree (siguid); xfree (issuer_fpr); } diff --git a/g10/pkclist.c b/g10/pkclist.c index dc19204..03ad4c8 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -113,7 +113,7 @@ void show_revocation_reason (ctrl_t ctrl, PKT_public_key *pk, int mode) { /* Hmmm, this is not so easy because we have to duplicate the code - * used in the trustbd to calculate the keyflags. We need to find + * used in the trustdb to calculate the keyflags. We need to find * a clean way to check revocation certificates on keys and * signatures. And there should be no duplicate code. Because we * enter this function only when the trustdb told us that we have commit 5c67ee160d4969b1ef94642ac602e1aed4d9a6d7 Author: Werner Koch Date: Thu Jun 21 15:06:30 2018 +0200 gpg: Let --show-keys print revocation certificates. * g10/import.c (list_standalone_revocation): New. (import_revoke_cert): Call new function. -- GnuPG-bug-id: 4018 Signed-off-by: Werner Koch (cherry picked from commit 386b9c4f25b28fd769d7563f2d86ac3a19cc3011) diff --git a/doc/DETAILS b/doc/DETAILS index 16e77c7..ce666da 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -59,6 +59,7 @@ described here. - uat :: User attribute (same as user id except for field 10). - sig :: Signature - rev :: Revocation signature + - rvs :: Recocation signature (standalone) [since 2.2.9] - fpr :: Fingerprint (fingerprint is in field 10) - pkd :: Public key data [*] - grp :: Keygrip @@ -207,12 +208,13 @@ described here. For "uid" records this field lists the preferences in the same way gpg's --edit-key menu does. - For "sig" records, this is the fingerprint of the key that issued - the signature. Note that this may only be filled if the signature - verified correctly. Note also that for various technical reasons, - this fingerprint is only available if --no-sig-cache is used. - Since 2.2.7 this field will also be set if the key is missing but - the signature carries an issuer fingerprint as meta data. + For "sig", "rev" and "rvs" records, this is the fingerprint of the + key that issued the signature. Note that this may only be filled + if the signature verified correctly. Note also that for various + technical reasons, this fingerprint is only available if + --no-sig-cache is used. Since 2.2.7 this field will also be set + if the key is missing but the signature carries an issuer + fingerprint as meta data. *** Field 14 - Flag field diff --git a/g10/import.c b/g10/import.c index ed3ada5..0f2ccfd 100644 --- a/g10/import.c +++ b/g10/import.c @@ -2613,6 +2613,95 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock, } + +/* List the recocation signature as a "rvs" record. SIGRC shows the + * character from the signature verification or 0 if no public key was + * found. */ +static void +list_standalone_revocation (ctrl_t ctrl, PKT_signature *sig, int sigrc) +{ + char *siguid = NULL; + size_t siguidlen = 0; + char *issuer_fpr = NULL; + + if (sigrc != '%' && sigrc != '?' && !opt.fast_list_mode) + { + int nouid; + siguid = get_user_id (ctrl, sig->keyid, &siguidlen, &nouid); + if (nouid) + sigrc = '?'; + } + + if (opt.with_colons) + { + es_fputs ("rvs:", es_stdout); + if (sigrc) + es_putc (sigrc, es_stdout); + es_fprintf (es_stdout, "::%d:%08lX%08lX:%s:%s:::", + sig->pubkey_algo, + (ulong) sig->keyid[0], (ulong) sig->keyid[1], + colon_datestr_from_sig (sig), + colon_expirestr_from_sig (sig)); + + if (siguid) + es_write_sanitized (es_stdout, siguid, siguidlen, ":", NULL); + + es_fprintf (es_stdout, ":%02x%c::", sig->sig_class, + sig->flags.exportable ? 'x' : 'l'); + + if ((issuer_fpr = issuer_fpr_string (sig))) + es_fputs (issuer_fpr, es_stdout); + + es_fprintf (es_stdout, ":::%d:\n", sig->digest_algo); + + if (opt.show_subpackets) + print_subpackets_colon (sig); + } + else /* Human readable. */ + { + es_fputs ("rvs", es_stdout); + es_fprintf (es_stdout, "%c%c %c%c%c%c%c%c %s %s", + sigrc, (sig->sig_class - 0x10 > 0 && + sig->sig_class - 0x10 < + 4) ? '0' + sig->sig_class - 0x10 : ' ', + sig->flags.exportable ? ' ' : 'L', + sig->flags.revocable ? ' ' : 'R', + sig->flags.policy_url ? 'P' : ' ', + sig->flags.notation ? 'N' : ' ', + sig->flags.expired ? 'X' : ' ', + (sig->trust_depth > 9) ? 'T' : (sig->trust_depth > + 0) ? '0' + + sig->trust_depth : ' ', keystr (sig->keyid), + datestr_from_sig (sig)); + if (siguid) + { + es_fprintf (es_stdout, " "); + print_utf8_buffer (es_stdout, siguid, siguidlen); + } + es_putc ('\n', es_stdout); + + if (sig->flags.policy_url + && (opt.list_options & LIST_SHOW_POLICY_URLS)) + show_policy_url (sig, 3, 0); + + if (sig->flags.notation && (opt.list_options & LIST_SHOW_NOTATIONS)) + show_notation (sig, 3, 0, + ((opt.list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0) + + + ((opt.list_options & LIST_SHOW_USER_NOTATIONS) ? 2 : 0)); + + if (sig->flags.pref_ks + && (opt.list_options & LIST_SHOW_KEYSERVER_URLS)) + show_keyserver_url (sig, 3, 0); + } + + es_fflush (es_stdout); + + xfree (siguid); + xfree (issuer_fpr); +} + + /**************** * Import a revocation certificate; this is a single signature packet. */ @@ -2626,6 +2715,11 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options, KEYDB_HANDLE hd = NULL; u32 keyid[2]; int rc = 0; + int sigrc = 0; + int silent; + + /* No error output for --show-keys. */ + silent = (options & (IMPORT_SHOW | IMPORT_DRY_RUN)); log_assert (!node->next ); log_assert (node->pkt->pkttype == PKT_SIGNATURE ); @@ -2638,15 +2732,16 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options, rc = get_pubkey (ctrl, pk, keyid ); if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY ) { - log_error(_("key %s: no public key -" - " can't apply revocation certificate\n"), keystr(keyid)); + if (!silent) + log_error (_("key %s: no public key -" + " can't apply revocation certificate\n"), keystr(keyid)); rc = 0; goto leave; } else if (rc ) { - log_error(_("key %s: public key not found: %s\n"), - keystr(keyid), gpg_strerror (rc)); + log_error (_("key %s: public key not found: %s\n"), + keystr(keyid), gpg_strerror (rc)); goto leave; } @@ -2683,12 +2778,21 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options, /* it is okay, that node is not in keyblock because * check_key_signature works fine for sig_class 0x20 (KEY_REV) in - * this special case. */ + * this special case. SIGRC is only used for IMPORT_SHOW. */ rc = check_key_signature (ctrl, keyblock, node, NULL); + switch (gpg_err_code (rc)) + { + case 0: sigrc = '!'; break; + case GPG_ERR_BAD_SIGNATURE: sigrc = '-'; break; + case GPG_ERR_NO_PUBKEY: sigrc = '?'; break; + case GPG_ERR_UNUSABLE_PUBKEY: sigrc = '?'; break; + default: sigrc = '%'; break; + } if (rc ) { - log_error( _("key %s: invalid revocation certificate" - ": %s - rejected\n"), keystr(keyid), gpg_strerror (rc)); + if (!silent) + log_error (_("key %s: invalid revocation certificate" + ": %s - rejected\n"), keystr(keyid), gpg_strerror (rc)); goto leave; } @@ -2738,6 +2842,9 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options, stats->n_revoc++; leave: + if ((options & IMPORT_SHOW)) + list_standalone_revocation (ctrl, node->pkt->pkt.signature, sigrc); + keydb_release (hd); release_kbnode( keyblock ); free_public_key( pk ); ----------------------------------------------------------------------- Summary of changes: doc/DETAILS | 23 ++++-- g10/gpgv.c | 15 ++++ g10/import.c | 236 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- g10/keylist.c | 72 ++++++++++++++++- g10/main.h | 3 + g10/pkclist.c | 2 +- g10/test-stubs.c | 14 ++++ 7 files changed, 347 insertions(+), 18 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 3 12:50:27 2018 From: cvs at cvs.gnupg.org (by Maximilian Krambach) Date: Tue, 03 Jul 2018 12:50:27 +0200 Subject: [git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-66-ga52ec87 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, javascript-binding has been updated via a52ec87d406379f1a6acd8d4f34605a4bac8683b (commit) from 88e7f8ec2ef3d90ca014b0bdb246f4d99f82abc8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit a52ec87d406379f1a6acd8d4f34605a4bac8683b Author: Maximilian Krambach Date: Tue Jul 3 12:41:49 2018 +0200 js: fixing Key import/export test -- * BrowserTestExtension: - The KeyImport/Export test had some errors, which have now been fixed - The secret key used for the test examples is now placed more prominently, and a clarification added that decrypt tests will not work if this key is not imported. * permittedOperations.js: typo Thanks to rrenkert at intevation.de for the fixes diff --git a/lang/js/BrowserTestExtension/index.html b/lang/js/BrowserTestExtension/index.html index 05d413b..7f8d97d 100644 --- a/lang/js/BrowserTestExtension/index.html +++ b/lang/js/BrowserTestExtension/index.html @@ -23,6 +23,15 @@ The functionality tests, to be found in gpgme/lang/js/BrowserTestExtension, check the overall functionality of the standard packaged version of gpgmejs. +

+

+ Most tests rely on a test gpg key to be available in gpg, which can be + found at the bottom of this page, or as "testkey.sec" in the + BrowserTestExtension's directory. Please import this key to your tested + gpg installation, or adapt the input defined in tests/inputvalues.js + if you want to use different values. +

+

+
+

+ + + +

diff --git a/lang/js/BrowserTestExtension/tests/KeyImportExport.js b/lang/js/BrowserTestExtension/tests/KeyImportExport.js index 6b29804..33e6bd2 100644 --- a/lang/js/BrowserTestExtension/tests/KeyImportExport.js +++ b/lang/js/BrowserTestExtension/tests/KeyImportExport.js @@ -19,6 +19,7 @@ * * Author(s): * Maximilian Krambach + * Raimund Renkert */ /* global describe, it, expect, Gpgmejs, ImportablePublicKey */ @@ -53,27 +54,27 @@ describe('Key importing', function () { expect(result.length).to.equal(0); context.Keyring.importKey(ImportablePublicKey.key, true) .then(function(result){ - expect(result[0]).to.not.be.undefined; - expect(result[0].key).to.be.an('object'); - expect(result[0].key.fingerprint).to.equal( + expect(result.Keys[0]).to.not.be.undefined; + expect(result.Keys[0].key).to.be.an('object'); + expect(result.Keys[0].key.fingerprint).to.equal( ImportablePublicKey.fingerprint); - expect(result[0].status).to.equal('newkey'); + expect(result.Keys[0].status).to.equal('newkey'); context.Keyring.importKey( ImportablePublicKey.keyChangedUserId,true) .then(function(res){ - expect(res[0]).to.not.be.undefined; - expect(res[0].key).to.be.an('object'); - expect(res[0].key.fingerprint).to.equal( + expect(res.Keys[0]).to.not.be.undefined; + expect(res.Keys[0].key).to.be.an('object'); + expect(res.Keys[0].key.fingerprint).to.equal( ImportablePublicKey.fingerprint); - expect(res[0].status).to.equal( + expect(res.Keys[0].status).to.equal( 'change'); expect( - res[0].changes.userId).to.be.true; + res.Keys[0].changes.userId).to.be.true; expect( - res[0].changes.subkey).to.be.false; + res.Keys[0].changes.subkey).to.be.false; expect( - res[0].changes.signature).to.be.true; - res[0].key.delete().then(function(result){ + res.Keys[0].changes.signature).to.be.true; + res.Keys[0].key.delete().then(function(result){ expect(result).to.be.true; done(); }); diff --git a/lang/js/src/permittedOperations.js b/lang/js/src/permittedOperations.js index 044ae4a..312eaa5 100644 --- a/lang/js/src/permittedOperations.js +++ b/lang/js/src/permittedOperations.js @@ -272,7 +272,7 @@ export const permittedOperations = { answer: { type: [], data: { - 'result': 'Object' + 'result': 'object' } } }, ----------------------------------------------------------------------- Summary of changes: lang/js/BrowserTestExtension/index.html | 73 ++++++++++++++++++++++ .../BrowserTestExtension/tests/KeyImportExport.js | 25 ++++---- lang/js/src/permittedOperations.js | 2 +- 3 files changed, 87 insertions(+), 13 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 3 16:22:04 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Tue, 03 Jul 2018 16:22:04 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-33-g61956b7 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via 61956b72ebf422d637c3aca934b4a027f791b862 (commit) via 541333d406df77b67cf520f80619ae92e3b92cbc (commit) from 87e96e7ee79ee837065883bb5434c9839024035f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 61956b72ebf422d637c3aca934b4a027f791b862 Author: Andre Heinecke Date: Tue Jul 3 16:21:38 2018 +0200 Remove now unused WinAPI dialog resource * src/dialogs.rc: Remove last winapi dialog. diff --git a/src/dialogs.rc b/src/dialogs.rc index 5687041..d5fc93e 100644 --- a/src/dialogs.rc +++ b/src/dialogs.rc @@ -57,138 +57,3 @@ IDI_SIGN_20_PNG RCDATA "icons/sign-20.png" IDI_GPGOL_LOCK_ICON ICON DISCARDABLE "icons/lock.ico" IDB_LOGO BITMAP DISCARDABLE "icons/logo.bmp" - -IDD_GPG_OPTIONS DIALOG DISCARDABLE 0, 0, 266, 274 -STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -CAPTION "GpgOL" -FONT 8, "MS Sans Serif" -BEGIN - /* General options box. */ - GROUPBOX "general-options", IDC_G_GENERAL, - 9, 9, 250, 25 - - CONTROL "enable-smime", IDC_ENABLE_SMIME, - "Button", BS_AUTOCHECKBOX | WS_TABSTOP, - 24, 19, 215, 10 - - /* Send options box. */ - GROUPBOX "send-options", IDC_G_SEND, - 9, 40, 250, 38 - - CONTROL "encrypt-by-default", IDC_ENCRYPT_DEFAULT, - "Button", BS_AUTOCHECKBOX | WS_TABSTOP, - 24, 50, 215, 10 - - CONTROL "sign-by-default", IDC_SIGN_DEFAULT, - "Button", BS_AUTOCHECKBOX | WS_TABSTOP, - 24, 61, 215, 10 - - /* Receive options box. */ - GROUPBOX "recv-options", IDC_G_RECV, - 9, 82, 250, 36 - - /* We have no reliable way to detect the preview window, thus we - don't show this option. */ -/* CONTROL "preview-decrypt", IDC_PREVIEW_DECRYPT, */ -/* "Button", BS_AUTOCHECKBOX | WS_TABSTOP, */ -/* 24, 114, 215, 10 */ - - CONTROL "prefer-html", IDC_PREFER_HTML, - "Button", BS_AUTOCHECKBOX | WS_TABSTOP, - 24, 94, 215, 10 - - CONTROL "body-as-attachment", IDC_BODY_AS_ATTACHMENT, - "Button", BS_AUTOCHECKBOX | WS_TABSTOP, - 24, 103, 215, 10 - - /* Stuff at the lower left corner. */ - LTEXT "GpgOL by g10 Code GmbH", IDC_G10CODE_STRING, - 8, 229, 100, 8 - LTEXT "Version x ", IDC_VERSION_INFO, - 8, 240, 100, 9 - - /* No more logo due to problems with the background colour. */ -/* CONTROL IDB_BANNER, IDC_BITMAP, */ -/* "Static", SS_BITMAP | SS_REALSIZEIMAGE, */ -/* 8, 212, 150, 64 */ - - PUSHBUTTON "advanced", IDC_GPG_OPTIONS, - 130, 240, 50, 14 - - PUSHBUTTON "gpgconf", IDC_GPG_CONF, - 190, 240, 70, 14 - -END - - - -IDD_EXT_OPTIONS DIALOG DISCARDABLE 0, 0, 155, 70 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION -CAPTION "GpgOL - Debug Options" -FONT 8, "MS Sans Serif" -BEGIN - LTEXT "debug-logfile", IDC_T_DEBUG_LOGFILE, - 8, 10, 122, 8 - - EDITTEXT IDC_DEBUG_LOGFILE, - 8, 20, 138, 12, ES_AUTOHSCROLL - - DEFPUSHBUTTON "&OK", IDOK, - 90, 50, 50, 14 -END - - -IDD_ADDIN_OPTIONS DIALOGEX DISCARDABLE 300, 300, 286, 190 -STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_SHELLFONT | DS_SETFONT -CAPTION "GpgOL" -FONT 8, "MS Shell Dlg" -BEGIN - /* General options box. */ - GROUPBOX "general-options", IDC_G_GENERAL, - 9, 9, 270, 25 - CONTROL "enable-smime", IDC_ENABLE_SMIME, - "Button", BS_AUTOCHECKBOX | WS_TABSTOP, - 24, 19, 235, 10 - - /* Send options box. */ - GROUPBOX "send-options", IDC_G_SEND, - 9, 50, 270, 67 - - CONTROL "encrypt-by-default", IDC_ENCRYPT_DEFAULT, - "Button", BS_AUTOCHECKBOX | WS_TABSTOP, - 24, 60, 235, 10 - - CONTROL "sign-by-default", IDC_SIGN_DEFAULT, - "Button", BS_AUTOCHECKBOX | WS_TABSTOP, - 24, 71, 235, 10 - - CONTROL "inline-pgp", IDC_INLINE_PGP, - "Button", BS_AUTOCHECKBOX | WS_TABSTOP, - 24, 82, 235, 10 - - CONTROL "replycrypt", IDC_REPLYCRYPT, - "Button", BS_AUTOCHECKBOX | WS_TABSTOP, - 24, 93, 235, 10 - - CONTROL "autoresolve", IDC_AUTORRESOLVE, - "Button", BS_AUTOCHECKBOX | WS_TABSTOP, - 24, 104, 235, 10 - - /* Stuff at the lower left corner. */ - CONTROL IDB_LOGO, IDC_BITMAP, - "Static", SS_BITMAP | SS_REALSIZEIMAGE, - 10, 125, 128, 80 - - LTEXT "Version x ", IDC_VERSION_INFO, - 10, 175, 100, 9 - - PUSHBUTTON "advanced", IDC_GPG_OPTIONS, - 180, 140, 90, 14 - - PUSHBUTTON "gpgconf", IDC_GPG_CONF, - 180, 155, 90, 14 - - DEFPUSHBUTTON "&OK", IDOK, - 180, 170, 90, 14 - -END commit 541333d406df77b67cf520f80619ae92e3b92cbc Author: Andre Heinecke Date: Tue Jul 3 16:14:43 2018 +0200 Change addion-options to use external dialog * src/addin-options.cpp (open_gpgolgui): New. (options_dialog_box): Open gpgolgui or bring it to foreground. (i18n_noops): Add strings. (launch_kleo_config): Removed. (options_window_proc): Removed. -- This adds a new config dialog which is a dynamic qt application. It uses the translations from GpgOL. GnuPG-Bug-Id: T3944 diff --git a/src/addin-options.cpp b/src/addin-options.cpp index bc36911..0286746 100644 --- a/src/addin-options.cpp +++ b/src/addin-options.cpp @@ -25,6 +25,8 @@ #include #include "dialogs.h" #include "common.h" +#include "cpphelp.h" +#include "oomhelp.h" #include @@ -36,178 +38,125 @@ __attribute__((__unused__)) static char const * i18n_noops[] = { N_("GnuPG System"), N_("Enable the S/MIME support"), + N_("Configure GpgOL"), + N_("Automation"), + N_("General"), + + N_("Automatically secure &messages"), + N_("Configure GnuPG"), + N_("Debug..."), + N_("Version "), + N_("&Resolve recipient keys automatically"), + N_("&Encrypt new messages by default"), + N_("&Sign new messages by default"), + N_("&Send OpenPGP mails without " + "attachments as PGP/Inline"), + N_("S&elect crypto settings automatically " + "for reply and forward"), + + /* Tooltips */ + N_("Enable or disable any automated key handling."), + N_("Automate trust based on communication history."), + N_("This changes the trust model to \"tofu+pgp\" which tracks the history of key usage. Automated trust can never exceed level 2."), + N_("experimental"), + N_("Automatically toggles secure if keys with at least level 1 trust were found for all recipients."), + N_("Toggles the encrypt option for all new mails."), + N_("Toggles the sign option for all new mails."), + N_("Toggles sign, encrypt options if the original mail was signed or encrypted."), + N_("Instead of using the PGP/MIME format, " + "which properly handles attachments and encoding, " + "the deprecated PGP/Inline is used.\n" + "This can be required for compatibility but should generally not " + "be used."), }; -/* To avoid writing a dialog template for each language we use gettext - for the labels and hope that there is enough space in the dialog to - fit the longest translation.. */ -static void -set_labels (HWND dlg) -{ - static struct { int itemid; const char *label; } labels[] = { - { IDC_G_GENERAL, N_("General")}, - { IDC_ENABLE_SMIME, N_("Enable the S/MIME support")}, - - { IDC_G_SEND, N_("Message sending")}, - { IDC_ENCRYPT_DEFAULT, N_("&Encrypt new messages by default")}, - { IDC_SIGN_DEFAULT, N_("&Sign new messages by default")}, - { IDC_INLINE_PGP, N_("&Send OpenPGP mails without " - "attachments as PGP/Inline")}, - { IDC_REPLYCRYPT, N_("S&elect crypto settings automatically " - "for reply and forward")}, - { IDC_AUTORRESOLVE, N_("&Resolve recipient keys automatically")}, - - - { IDC_GPG_OPTIONS, N_("Debug...")}, - { IDC_GPG_CONF, N_("Configure GnuPG")}, - { IDC_VERSION_INFO, N_("Version ")VERSION}, - { 0, NULL} - }; - int i; - - for (i=0; labels[i].itemid; i++) - SetDlgItemText (dlg, labels[i].itemid, _(labels[i].label)); -} +static bool dlg_open; -static void -launch_kleo_config (HWND hDlg) +static DWORD WINAPI +open_gpgolgui (LPVOID arg) { - char *uiserver = get_uiserver_name (); - bool showError = false; - if (uiserver) + HWND wnd = (HWND) arg; + + std::vector args; + + // Collect the arguments + char *gpg4win_dir = get_gpg4win_dir (); + if (!gpg4win_dir) { - std::string path (uiserver); - xfree (uiserver); - if (path.find("kleopatra.exe") != std::string::npos) - { - size_t dpos; - if ((dpos = path.find(" --daemon")) != std::string::npos) - { - path.erase(dpos, strlen(" --daemon")); - } - auto ctx = GpgME::Context::createForEngine(GpgME::SpawnEngine); - if (!ctx) - { - log_error ("%s:%s: No spawn engine.", - SRCNAME, __func__); - } - std::string parentWid = std::to_string ((int) (intptr_t) hDlg); - const char *argv[] = {path.c_str(), - "--config", - "--parent-windowid", - parentWid.c_str(), - NULL }; - log_debug ("%s:%s: Starting %s %s %s", - SRCNAME, __func__, path.c_str(), argv[1], argv[2]); - GpgME::Data d(GpgME::Data::null); - ctx->spawnAsync(path.c_str(), argv, d, d, - d, (GpgME::Context::SpawnFlags) ( - GpgME::Context::SpawnAllowSetFg | - GpgME::Context::SpawnShowWindow)); - } - else - { - showError = true; - } + TRACEPOINT; + return -1; } - else + const auto gpgolgui = std::string (gpg4win_dir) + "\\bin\\gpgolgui.exe"; + args.push_back (gpgolgui); + + args.push_back (std::string ("--hwnd")); + args.push_back (std::to_string ((int) (intptr_t) wnd)); + + args.push_back (std::string("--gpgol-version")); + args.push_back (std::string(VERSION)); + + auto ctx = GpgME::Context::createForEngine (GpgME::SpawnEngine); + if (!ctx) { - showError = true; + // can't happen + TRACEPOINT; + return -1; } - if (showError) + GpgME::Data mystdin (GpgME::Data::null), mystdout, mystderr; + dlg_open = true; + + char **cargs = vector_to_cArray (args); + log_debug ("%s:%s: args:", SRCNAME, __func__); + for (size_t i = 0; cargs && cargs[i]; i++) { - MessageBox (NULL, - _("Could not find Kleopatra.\n" - "Please reinstall Gpg4win with the Kleopatra component enabled."), - _("GpgOL"), - MB_ICONINFORMATION|MB_OK); + log_debug (SIZE_T_FORMAT ": '%s'", i, cargs[i]); } -} - -static INT_PTR CALLBACK -options_window_proc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - (void)lParam; - switch (uMsg) + GpgME::Error err = ctx->spawn (cargs[0], const_cast (cargs), + mystdin, mystdout, mystderr, + (GpgME::Context::SpawnFlags) ( + GpgME::Context::SpawnAllowSetFg | + GpgME::Context::SpawnShowWindow)); + if (err) { - case WM_INITDIALOG: - { - SendDlgItemMessage (hDlg, IDC_ENABLE_SMIME, BM_SETCHECK, - !!opt.enable_smime, 0L); - SendDlgItemMessage (hDlg, IDC_ENCRYPT_DEFAULT, BM_SETCHECK, - !!opt.encrypt_default, 0L); - SendDlgItemMessage (hDlg, IDC_SIGN_DEFAULT, BM_SETCHECK, - !!opt.sign_default, 0L); - SendDlgItemMessage (hDlg, IDC_INLINE_PGP, BM_SETCHECK, - !!opt.inline_pgp, 0L); - SendDlgItemMessage (hDlg, IDC_REPLYCRYPT, BM_SETCHECK, - !!opt.reply_crypt, 0L); - SendDlgItemMessage (hDlg, IDC_AUTORRESOLVE, BM_SETCHECK, - !!opt.autoresolve, 0L); - set_labels (hDlg); - ShowWindow (GetDlgItem (hDlg, IDC_GPG_OPTIONS), - opt.enable_debug ? SW_SHOW : SW_HIDE); - } - return 1; - case WM_LBUTTONDOWN: - { - return 1; - } - case WM_COMMAND: - switch (LOWORD (wParam)) - { - case IDOK: - { - opt.enable_smime = !!SendDlgItemMessage - (hDlg, IDC_ENABLE_SMIME, BM_GETCHECK, 0, 0L); - - opt.encrypt_default = !!SendDlgItemMessage - (hDlg, IDC_ENCRYPT_DEFAULT, BM_GETCHECK, 0, 0L); - opt.sign_default = !!SendDlgItemMessage - (hDlg, IDC_SIGN_DEFAULT, BM_GETCHECK, 0, 0L); - opt.inline_pgp = !!SendDlgItemMessage - (hDlg, IDC_INLINE_PGP, BM_GETCHECK, 0, 0L); - - opt.reply_crypt = !!SendDlgItemMessage - (hDlg, IDC_REPLYCRYPT, BM_GETCHECK, 0, 0L); - - opt.autoresolve = !!SendDlgItemMessage - (hDlg, IDC_AUTORRESOLVE, BM_GETCHECK, 0, 0L); - - write_options (); - EndDialog (hDlg, TRUE); - break; - } - case IDC_GPG_CONF: - launch_kleo_config (hDlg); - break; - case IDC_GPG_OPTIONS: - config_dialog_box (hDlg); - break; - } - case WM_SYSCOMMAND: - switch (LOWORD (wParam)) - { - case SC_CLOSE: - EndDialog (hDlg, TRUE); - } - - break; + log_error ("%s:%s: Err code: %i asString: %s", + SRCNAME, __func__, err.code(), err.asString()); } + dlg_open = false; + + log_debug ("%s:%s:finished stdout:\n'%s'", + SRCNAME, __func__, mystdout.toString ().c_str ()); + log_debug ("%s:%s:stderr:\n'%s'", + SRCNAME, __func__, mystderr.toString ().c_str ()); + read_options (); return 0; } void options_dialog_box (HWND parent) { - int resid; + if (!parent) + parent = get_active_hwnd (); - resid = IDD_ADDIN_OPTIONS; + if (dlg_open) + { + log_debug ("%s:%s: Gpgolgui open. Not launching new dialog.", + SRCNAME, __func__); + HWND optWindow = FindWindow (nullptr, _("Configure GpgOL")); + if (!optWindow) { + log_debug ("%s:%s: Gpgolgui open but could not find window.", + SRCNAME, __func__); + return; + } + SetForegroundWindow(optWindow); + + return; + } - if (!parent) - parent = GetDesktopWindow (); - DialogBoxParam (glob_hinst, MAKEINTRESOURCE (resid), parent, - options_window_proc, 0); + log_debug ("%s:%s: Launching gpgolgui.", + SRCNAME, __func__); + + CloseHandle (CreateThread (NULL, 0, open_gpgolgui, (LPVOID) parent, 0, + NULL)); } ----------------------------------------------------------------------- Summary of changes: src/addin-options.cpp | 253 ++++++++++++++++++++------------------------------ src/dialogs.rc | 135 --------------------------- 2 files changed, 101 insertions(+), 287 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 4 07:10:32 2018 From: cvs at cvs.gnupg.org (by NIIBE Yutaka) Date: Wed, 04 Jul 2018 07:10:32 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.8.1-85-g9660c3f Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via 9660c3fafd732b1857bb2697c6f43aed077b9ad6 (commit) from 8a44c55d2fb758f726b8b436aa5c0b88a6c6f112 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 9660c3fafd732b1857bb2697c6f43aed077b9ad6 Author: NIIBE Yutaka Date: Wed Jul 4 14:09:38 2018 +0900 RFC-8439 was published. * cipher/cipher-poly1305.c: Update RFC reference. Signed-off-by: NIIBE Yutaka diff --git a/cipher/cipher-poly1305.c b/cipher/cipher-poly1305.c index a2a74e8..82537aa 100644 --- a/cipher/cipher-poly1305.c +++ b/cipher/cipher-poly1305.c @@ -1,4 +1,4 @@ -/* cipher-poly1305.c - Poly1305 based AEAD cipher mode, RFC-7539 +/* cipher-poly1305.c - Poly1305 based AEAD cipher mode, RFC-8439 * Copyright (C) 2014 Jussi Kivilinna * * This file is part of Libgcrypt. diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 967745f..4cae489 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -1690,7 +1690,7 @@ Associated Data (AEAD) block cipher mode, which is specified in @item GCRY_CIPHER_MODE_POLY1305 @cindex Poly1305 based AEAD mode with ChaCha20 This mode implements the Poly1305 Authenticated Encryption with Associated -Data (AEAD) mode according to RFC-7539. This mode can be used with ChaCha20 +Data (AEAD) mode according to RFC-8439. This mode can be used with ChaCha20 stream cipher. @item GCRY_CIPHER_MODE_OCB ----------------------------------------------------------------------- Summary of changes: cipher/cipher-poly1305.c | 2 +- doc/gcrypt.texi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 4 09:09:19 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Wed, 04 Jul 2018 09:09:19 +0200 Subject: [git] GnuPG - branch, master, updated. gnupg-2.2.7-168-g214b007 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 214b0077264e35c079e854a8b6374704aea45cd5 (commit) from 996febbab21eb9283b0634e51303a36b318734a6 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 214b0077264e35c079e854a8b6374704aea45cd5 Author: Werner Koch Date: Wed Jul 4 08:59:12 2018 +0200 gpg: Extra check for sign usage when verifying a data signature. * g10/sig-check.c (check_signature_end_simple): Check sign usage. -- Without this patch the signature verification fails only due to the missing back signature. This check better explains what went wrong. GnuPG-bug-id: 4014 Signed-off-by: Werner Koch diff --git a/g10/sig-check.c b/g10/sig-check.c index fc69839..a68e031 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -478,8 +478,17 @@ check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig, sig->sig_class, pk->pubkey_usage); return rc; } - /* Fixme: Should we also check the signing capability here for data - * signature? */ + + /* For data signatures check that the key has sign usage. */ + if (IS_SIG (sig) && !(pk->pubkey_usage & PUBKEY_USAGE_SIG)) + { + rc = gpg_error (GPG_ERR_WRONG_KEY_USAGE); + if (!opt.quiet) + log_info (_("bad data signature from key %s: %s (0x%02x, 0x%x)\n"), + keystr_from_pk (pk), gpg_strerror (rc), + sig->sig_class, pk->pubkey_usage); + return rc; + } /* Make sure the digest algo is enabled (in case of a detached * signature). */ ----------------------------------------------------------------------- Summary of changes: g10/sig-check.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 4 09:11:02 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Wed, 04 Jul 2018 09:11:02 +0200 Subject: [git] GnuPG - branch, STABLE-BRANCH-2-2, updated. gnupg-2.2.8-18-gef50fdf Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, STABLE-BRANCH-2-2 has been updated via ef50fdf82a459894ed3da7b9be83f89658f1eaba (commit) from 04fb76684d8b2c9cda2e5c35bad6edec521cffa5 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit ef50fdf82a459894ed3da7b9be83f89658f1eaba Author: Werner Koch Date: Wed Jul 4 08:59:12 2018 +0200 gpg: Extra check for sign usage when verifying a data signature. * g10/sig-check.c (check_signature_end_simple): Check sign usage. -- Without this patch the signature verification fails only due to the missing back signature. This check better explains what went wrong. GnuPG-bug-id: 4014 Signed-off-by: Werner Koch (cherry picked from commit 214b0077264e35c079e854a8b6374704aea45cd5) diff --git a/g10/sig-check.c b/g10/sig-check.c index e5de025..6b9feeb 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -479,8 +479,17 @@ check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig, sig->sig_class, pk->pubkey_usage); return rc; } - /* Fixme: Should we also check the signing capability here for data - * signature? */ + + /* For data signatures check that the key has sign usage. */ + if (IS_SIG (sig) && !(pk->pubkey_usage & PUBKEY_USAGE_SIG)) + { + rc = gpg_error (GPG_ERR_WRONG_KEY_USAGE); + if (!opt.quiet) + log_info (_("bad data signature from key %s: %s (0x%02x, 0x%x)\n"), + keystr_from_pk (pk), gpg_strerror (rc), + sig->sig_class, pk->pubkey_usage); + return rc; + } /* Make sure the digest algo is enabled (in case of a detached * signature). */ ----------------------------------------------------------------------- Summary of changes: g10/sig-check.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 4 10:15:29 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Wed, 04 Jul 2018 10:15:29 +0200 Subject: [git] GnuPG - branch, master, updated. gnupg-2.2.7-170-g01cd66f Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 01cd66f9faf1623833e6afac84164de5a136ecff (commit) via 60e7e102a153a246d7e887a64e30dbb4c4f7b6dd (commit) from 214b0077264e35c079e854a8b6374704aea45cd5 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 01cd66f9faf1623833e6afac84164de5a136ecff Author: Werner Koch Date: Wed Jul 4 09:53:10 2018 +0200 gpg: Ignore too large user ids during import. * g10/import.c (read_block): Add special treatment for bad user ids and comment packets. -- See GnuPG-bug-id: 4022 for an example of a bogus user id. Signed-off-by: Werner Koch diff --git a/g10/import.c b/g10/import.c index 62bc6a2..5be7952 100644 --- a/g10/import.c +++ b/g10/import.c @@ -780,7 +780,7 @@ read_block( IOBUF a, int with_meta, struct parse_packet_ctx_s parsectx; PACKET *pkt; kbnode_t root = NULL; - int in_cert, in_v3key; + int in_cert, in_v3key, skip_sigs; *r_v3keys = 0; @@ -799,6 +799,7 @@ read_block( IOBUF a, int with_meta, if (!with_meta) parsectx.skip_meta = 1; in_v3key = 0; + skip_sigs = 0; while ((rc=parse_packet (&parsectx, pkt)) != -1) { if (rc && (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY @@ -813,8 +814,25 @@ read_block( IOBUF a, int with_meta, } else if (rc ) /* (ignore errors) */ { + skip_sigs = 0; if (gpg_err_code (rc) == GPG_ERR_UNKNOWN_PACKET) ; /* Do not show a diagnostic. */ + else if (gpg_err_code (rc) == GPG_ERR_INV_PACKET + && (pkt->pkttype == PKT_USER_ID + || pkt->pkttype == PKT_ATTRIBUTE)) + { + /* This indicates a too large user id or attribute + * packet. We skip this packet and all following + * signatures. Sure, this won't allow to repair a + * garbled keyring in case one of the signatures belong + * to another user id. However, this better mitigates + * DoS using inserted user ids. */ + skip_sigs = 1; + } + else if (gpg_err_code (rc) == GPG_ERR_INV_PACKET + && (pkt->pkttype == PKT_OLD_COMMENT + || pkt->pkttype == PKT_COMMENT)) + ; /* Ignore too large comment packets. */ else { log_error("read_block: read error: %s\n", gpg_strerror (rc) ); @@ -826,6 +844,17 @@ read_block( IOBUF a, int with_meta, continue; } + if (skip_sigs) + { + if (pkt->pkttype == PKT_SIGNATURE) + { + free_packet (pkt, &parsectx); + init_packet (pkt); + continue; + } + skip_sigs = 0; + } + if (in_v3key && !(pkt->pkttype == PKT_PUBLIC_KEY || pkt->pkttype == PKT_SECRET_KEY)) { commit 60e7e102a153a246d7e887a64e30dbb4c4f7b6dd Author: Werner Koch Date: Wed Jul 4 09:45:52 2018 +0200 indent: Fix indentation of read_block in g10/import.c -- Signed-off-by: Werner Koch diff --git a/g10/import.c b/g10/import.c index b20879c..62bc6a2 100644 --- a/g10/import.c +++ b/g10/import.c @@ -826,76 +826,77 @@ read_block( IOBUF a, int with_meta, continue; } - if (in_v3key && !(pkt->pkttype == PKT_PUBLIC_KEY - || pkt->pkttype == PKT_SECRET_KEY)) - { - free_packet (pkt, &parsectx); - init_packet(pkt); - continue; - } - in_v3key = 0; + if (in_v3key && !(pkt->pkttype == PKT_PUBLIC_KEY + || pkt->pkttype == PKT_SECRET_KEY)) + { + free_packet (pkt, &parsectx); + init_packet(pkt); + continue; + } + in_v3key = 0; - if (!root && pkt->pkttype == PKT_SIGNATURE - && IS_KEY_REV (pkt->pkt.signature) ) - { - /* This is a revocation certificate which is handled in a - * special way. */ - root = new_kbnode( pkt ); - pkt = NULL; - goto ready; - } + if (!root && pkt->pkttype == PKT_SIGNATURE + && IS_KEY_REV (pkt->pkt.signature) ) + { + /* This is a revocation certificate which is handled in a + * special way. */ + root = new_kbnode( pkt ); + pkt = NULL; + goto ready; + } - /* Make a linked list of all packets. */ - switch (pkt->pkttype) - { - case PKT_COMPRESSED: - if (check_compress_algo (pkt->pkt.compressed->algorithm)) - { - rc = GPG_ERR_COMPR_ALGO; - goto ready; - } - else - { - compress_filter_context_t *cfx = xmalloc_clear( sizeof *cfx ); - pkt->pkt.compressed->buf = NULL; - if (push_compress_filter2 (a, cfx, - pkt->pkt.compressed->algorithm, 1)) - xfree (cfx); /* e.g. in case of compression_algo NONE. */ - } - free_packet (pkt, &parsectx); - init_packet(pkt); - break; + /* Make a linked list of all packets. */ + switch (pkt->pkttype) + { + case PKT_COMPRESSED: + if (check_compress_algo (pkt->pkt.compressed->algorithm)) + { + rc = GPG_ERR_COMPR_ALGO; + goto ready; + } + else + { + compress_filter_context_t *cfx = xmalloc_clear( sizeof *cfx ); + pkt->pkt.compressed->buf = NULL; + if (push_compress_filter2 (a, cfx, + pkt->pkt.compressed->algorithm, 1)) + xfree (cfx); /* e.g. in case of compression_algo NONE. */ + } + free_packet (pkt, &parsectx); + init_packet(pkt); + break; - case PKT_RING_TRUST: - /* Skip those packets unless we are in restore mode. */ - if ((opt.import_options & IMPORT_RESTORE)) - goto x_default; - free_packet (pkt, &parsectx); - init_packet(pkt); - break; + case PKT_RING_TRUST: + /* Skip those packets unless we are in restore mode. */ + if ((opt.import_options & IMPORT_RESTORE)) + goto x_default; + free_packet (pkt, &parsectx); + init_packet(pkt); + break; - case PKT_PUBLIC_KEY: - case PKT_SECRET_KEY: - if (in_cert ) /* Store this packet. */ - { - *pending_pkt = pkt; - pkt = NULL; - goto ready; - } - in_cert = 1; /* fall through */ - default: - x_default: - if (in_cert && valid_keyblock_packet (pkt->pkttype)) - { - if (!root ) - root = new_kbnode (pkt); - else - add_kbnode (root, new_kbnode (pkt)); - pkt = xmalloc (sizeof *pkt); - } - init_packet(pkt); - break; - } + case PKT_PUBLIC_KEY: + case PKT_SECRET_KEY: + if (in_cert ) /* Store this packet. */ + { + *pending_pkt = pkt; + pkt = NULL; + goto ready; + } + in_cert = 1; + /* fall through */ + default: + x_default: + if (in_cert && valid_keyblock_packet (pkt->pkttype)) + { + if (!root ) + root = new_kbnode (pkt); + else + add_kbnode (root, new_kbnode (pkt)); + pkt = xmalloc (sizeof *pkt); + } + init_packet(pkt); + break; + } } ready: ----------------------------------------------------------------------- Summary of changes: g10/import.c | 164 +++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 97 insertions(+), 67 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 4 10:18:59 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Wed, 04 Jul 2018 10:18:59 +0200 Subject: [git] GnuPG - branch, STABLE-BRANCH-2-2, updated. gnupg-2.2.8-20-gcb6b925 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, STABLE-BRANCH-2-2 has been updated via cb6b925f94b42c91fe8a7ed8bb22d98984538efc (commit) via 5b47b4613221b1fd38af3281a8cf71d78adf4de8 (commit) from ef50fdf82a459894ed3da7b9be83f89658f1eaba (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit cb6b925f94b42c91fe8a7ed8bb22d98984538efc Author: Werner Koch Date: Wed Jul 4 09:53:10 2018 +0200 gpg: Ignore too large user ids during import. * g10/import.c (read_block): Add special treatment for bad user ids and comment packets. -- See GnuPG-bug-id: 4022 for an example of a bogus user id. Signed-off-by: Werner Koch (cherry picked from commit 01cd66f9faf1623833e6afac84164de5a136ecff) diff --git a/g10/import.c b/g10/import.c index 6fadf44..b43060d 100644 --- a/g10/import.c +++ b/g10/import.c @@ -780,7 +780,7 @@ read_block( IOBUF a, int with_meta, struct parse_packet_ctx_s parsectx; PACKET *pkt; kbnode_t root = NULL; - int in_cert, in_v3key; + int in_cert, in_v3key, skip_sigs; *r_v3keys = 0; @@ -799,6 +799,7 @@ read_block( IOBUF a, int with_meta, if (!with_meta) parsectx.skip_meta = 1; in_v3key = 0; + skip_sigs = 0; while ((rc=parse_packet (&parsectx, pkt)) != -1) { if (rc && (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY @@ -813,8 +814,25 @@ read_block( IOBUF a, int with_meta, } else if (rc ) /* (ignore errors) */ { + skip_sigs = 0; if (gpg_err_code (rc) == GPG_ERR_UNKNOWN_PACKET) ; /* Do not show a diagnostic. */ + else if (gpg_err_code (rc) == GPG_ERR_INV_PACKET + && (pkt->pkttype == PKT_USER_ID + || pkt->pkttype == PKT_ATTRIBUTE)) + { + /* This indicates a too large user id or attribute + * packet. We skip this packet and all following + * signatures. Sure, this won't allow to repair a + * garbled keyring in case one of the signatures belong + * to another user id. However, this better mitigates + * DoS using inserted user ids. */ + skip_sigs = 1; + } + else if (gpg_err_code (rc) == GPG_ERR_INV_PACKET + && (pkt->pkttype == PKT_OLD_COMMENT + || pkt->pkttype == PKT_COMMENT)) + ; /* Ignore too large comment packets. */ else { log_error("read_block: read error: %s\n", gpg_strerror (rc) ); @@ -826,6 +844,17 @@ read_block( IOBUF a, int with_meta, continue; } + if (skip_sigs) + { + if (pkt->pkttype == PKT_SIGNATURE) + { + free_packet (pkt, &parsectx); + init_packet (pkt); + continue; + } + skip_sigs = 0; + } + if (in_v3key && !(pkt->pkttype == PKT_PUBLIC_KEY || pkt->pkttype == PKT_SECRET_KEY)) { commit 5b47b4613221b1fd38af3281a8cf71d78adf4de8 Author: Werner Koch Date: Wed Jul 4 09:45:52 2018 +0200 indent: Fix indentation of read_block in g10/import.c -- Signed-off-by: Werner Koch (cherry picked from commit 60e7e102a153a246d7e887a64e30dbb4c4f7b6dd) diff --git a/g10/import.c b/g10/import.c index 49381d4..6fadf44 100644 --- a/g10/import.c +++ b/g10/import.c @@ -826,76 +826,77 @@ read_block( IOBUF a, int with_meta, continue; } - if (in_v3key && !(pkt->pkttype == PKT_PUBLIC_KEY - || pkt->pkttype == PKT_SECRET_KEY)) - { - free_packet (pkt, &parsectx); - init_packet(pkt); - continue; - } - in_v3key = 0; + if (in_v3key && !(pkt->pkttype == PKT_PUBLIC_KEY + || pkt->pkttype == PKT_SECRET_KEY)) + { + free_packet (pkt, &parsectx); + init_packet(pkt); + continue; + } + in_v3key = 0; - if (!root && pkt->pkttype == PKT_SIGNATURE - && IS_KEY_REV (pkt->pkt.signature) ) - { - /* This is a revocation certificate which is handled in a - * special way. */ - root = new_kbnode( pkt ); - pkt = NULL; - goto ready; - } + if (!root && pkt->pkttype == PKT_SIGNATURE + && IS_KEY_REV (pkt->pkt.signature) ) + { + /* This is a revocation certificate which is handled in a + * special way. */ + root = new_kbnode( pkt ); + pkt = NULL; + goto ready; + } - /* Make a linked list of all packets. */ - switch (pkt->pkttype) - { - case PKT_COMPRESSED: - if (check_compress_algo (pkt->pkt.compressed->algorithm)) - { - rc = GPG_ERR_COMPR_ALGO; - goto ready; - } - else - { - compress_filter_context_t *cfx = xmalloc_clear( sizeof *cfx ); - pkt->pkt.compressed->buf = NULL; - if (push_compress_filter2 (a, cfx, - pkt->pkt.compressed->algorithm, 1)) - xfree (cfx); /* e.g. in case of compression_algo NONE. */ - } - free_packet (pkt, &parsectx); - init_packet(pkt); - break; + /* Make a linked list of all packets. */ + switch (pkt->pkttype) + { + case PKT_COMPRESSED: + if (check_compress_algo (pkt->pkt.compressed->algorithm)) + { + rc = GPG_ERR_COMPR_ALGO; + goto ready; + } + else + { + compress_filter_context_t *cfx = xmalloc_clear( sizeof *cfx ); + pkt->pkt.compressed->buf = NULL; + if (push_compress_filter2 (a, cfx, + pkt->pkt.compressed->algorithm, 1)) + xfree (cfx); /* e.g. in case of compression_algo NONE. */ + } + free_packet (pkt, &parsectx); + init_packet(pkt); + break; - case PKT_RING_TRUST: - /* Skip those packets unless we are in restore mode. */ - if ((opt.import_options & IMPORT_RESTORE)) - goto x_default; - free_packet (pkt, &parsectx); - init_packet(pkt); - break; + case PKT_RING_TRUST: + /* Skip those packets unless we are in restore mode. */ + if ((opt.import_options & IMPORT_RESTORE)) + goto x_default; + free_packet (pkt, &parsectx); + init_packet(pkt); + break; - case PKT_PUBLIC_KEY: - case PKT_SECRET_KEY: - if (in_cert ) /* Store this packet. */ - { - *pending_pkt = pkt; - pkt = NULL; - goto ready; - } - in_cert = 1; /* fall through */ - default: - x_default: - if (in_cert && valid_keyblock_packet (pkt->pkttype)) - { - if (!root ) - root = new_kbnode (pkt); - else - add_kbnode (root, new_kbnode (pkt)); - pkt = xmalloc (sizeof *pkt); - } - init_packet(pkt); - break; - } + case PKT_PUBLIC_KEY: + case PKT_SECRET_KEY: + if (in_cert ) /* Store this packet. */ + { + *pending_pkt = pkt; + pkt = NULL; + goto ready; + } + in_cert = 1; + /* fall through */ + default: + x_default: + if (in_cert && valid_keyblock_packet (pkt->pkttype)) + { + if (!root ) + root = new_kbnode (pkt); + else + add_kbnode (root, new_kbnode (pkt)); + pkt = xmalloc (sizeof *pkt); + } + init_packet(pkt); + break; + } } ready: ----------------------------------------------------------------------- Summary of changes: g10/import.c | 164 +++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 97 insertions(+), 67 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 4 11:17:00 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Wed, 04 Jul 2018 11:17:00 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-77-g76b8470 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 76b847091593669c8a7e38918267d6be97dbd4d0 (commit) from 5bca49975063f788b2499342d5a565faf54511db (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 76b847091593669c8a7e38918267d6be97dbd4d0 Author: Andre Heinecke Date: Wed Jul 4 11:13:26 2018 +0200 json: Add keylist mode locate * src/gpgme-json.c (op_keylist, hlp_keylist): Add locate. -- The same rationale for the KEYLIST_MODE_LOCATE in GPGME also applies here. It makes the API a little less magic. diff --git a/src/gpgme-json.c b/src/gpgme-json.c index d7e1cbc..8d534c6 100644 --- a/src/gpgme-json.c +++ b/src/gpgme-json.c @@ -2125,6 +2125,7 @@ static const char hlp_keylist[] = "tofu: Add KEYLIST_MODE_WITH_TOFU.\n" "ephemeral: Add KEYLIST_MODE_EPHEMERAL.\n" "validate: Add KEYLIST_MODE_VALIDATE.\n" + "locate: Add KEYLIST_MODE_LOCATE.\n" "\n" "Response on success:\n" "keys: Array of keys.\n" @@ -2290,6 +2291,11 @@ op_keylist (cjson_t request, cjson_t result) if (abool) mode |= GPGME_KEYLIST_MODE_VALIDATE; + if ((err = get_boolean_flag (request, "locate", 0, &abool))) + goto leave; + if (abool) + mode |= GPGME_KEYLIST_MODE_LOCATE; + if (!mode) { /* default to local */ ----------------------------------------------------------------------- Summary of changes: src/gpgme-json.c | 6 ++++++ 1 file changed, 6 insertions(+) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 4 12:13:06 2018 From: cvs at cvs.gnupg.org (by Maximilian Krambach) Date: Wed, 04 Jul 2018 12:13:06 +0200 Subject: [git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-67-g1105fc8 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, javascript-binding has been updated via 1105fc87a3bd3e1152aff578b7b84871558418e6 (commit) from a52ec87d406379f1a6acd8d4f34605a4bac8683b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 1105fc87a3bd3e1152aff578b7b84871558418e6 Author: Maximilian Krambach Date: Wed Jul 4 12:11:35 2018 +0200 js: add Key lookup -- * src/Keyring.js: getKeys() now has the option "search", which will trigger a remote lookup (as configured in gpg) for the string given as pattern. * src/permittedOperations: make use of the new 'locate' option in keylist * DemoExtension: Add a button for lookup, to demonstrate the functionality diff --git a/lang/js/DemoExtension/maindemo.js b/lang/js/DemoExtension/maindemo.js index d0127c7..4cae934 100644 --- a/lang/js/DemoExtension/maindemo.js +++ b/lang/js/DemoExtension/maindemo.js @@ -98,5 +98,22 @@ document.addEventListener('DOMContentLoaded', function() { alert( errormsg.message); }); }); + document.getElementById('searchkey').addEventListener('click', + function(){ + let data = document.getElementById('inputtext').value; + gpgmejs.Keyring.getKeys(data, true, true).then(function(keys){ + if (keys.length === 1){ + document.getElementById( + 'pubkey').value = keys[0].fingerprint; + } else if (keys.length > 1) { + alert('The pattern was not unambigious enough for a Key. ' + + keys.length + ' Keys were found'); + } else { + alert('No keys found'); + } + }, function(errormsg){ + alert( errormsg.message); + }); + }); }); }); diff --git a/lang/js/DemoExtension/mainui.html b/lang/js/DemoExtension/mainui.html index b639036..c773c9b 100644 --- a/lang/js/DemoExtension/mainui.html +++ b/lang/js/DemoExtension/mainui.html @@ -17,9 +17,13 @@
  • Fingerprint of Key to use: -
  • -
    - + +   + diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index 8bec1ce..0d7643f 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -39,16 +39,21 @@ export class GPGME_Keyring { * inmediately. This allows for full synchronous use. If set to false, * these will initially only be available as Promises in getArmor() and * getHasSecret() + * @param {Boolean} search (optional) retrieve the Keys from servers with + * the method(s) defined in gnupg (e.g. WKD/HKP lookup) * @returns {Promise.>} * */ - getKeys(pattern, prepare_sync){ + getKeys(pattern, prepare_sync, search){ return new Promise(function(resolve, reject) { let msg = createMessage('keylist'); if (pattern !== undefined){ msg.setParameter('keys', pattern); } msg.setParameter('sigs', true); + if (search === true){ + msg.setParameter('locate', true); + } msg.post().then(function(result){ let resultset = []; let promises = []; diff --git a/lang/js/src/permittedOperations.js b/lang/js/src/permittedOperations.js index 312eaa5..e7f5396 100644 --- a/lang/js/src/permittedOperations.js +++ b/lang/js/src/permittedOperations.js @@ -188,6 +188,9 @@ export const permittedOperations = { 'local':{ allowed: ['boolean'] }, + 'locate': { + allowed: ['boolean'] + }, 'sigs':{ allowed: ['boolean'] }, ----------------------------------------------------------------------- Summary of changes: lang/js/DemoExtension/maindemo.js | 17 +++++++++++++++++ lang/js/DemoExtension/mainui.html | 10 +++++++--- lang/js/src/Keyring.js | 7 ++++++- lang/js/src/permittedOperations.js | 3 +++ 4 files changed, 33 insertions(+), 4 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 4 12:18:15 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Wed, 04 Jul 2018 12:18:15 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-78-g7d65dc2 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 7d65dc2a5c4f32139a1b9b1f0bd375f7ab1c58f6 (commit) from 76b847091593669c8a7e38918267d6be97dbd4d0 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 7d65dc2a5c4f32139a1b9b1f0bd375f7ab1c58f6 Author: Andre Heinecke Date: Wed Jul 4 12:15:05 2018 +0200 cpp: Fix memory of DecryptionResult::symkeyAlgo * lang/cpp/src/decryptionresult.cpp (Private, ~Private): strdup the symkey algo. diff --git a/lang/cpp/src/decryptionresult.cpp b/lang/cpp/src/decryptionresult.cpp index de58921..ea0a8a5 100644 --- a/lang/cpp/src/decryptionresult.cpp +++ b/lang/cpp/src/decryptionresult.cpp @@ -51,6 +51,9 @@ public: if (res.file_name) { res.file_name = strdup(res.file_name); } + if (res.symkey_algo) { + res.symkey_algo = strdup(res.symkey_algo); + } //FIXME: copying gpgme_recipient_t objects invalidates the keyid member, //thus we use _keyid for now (internal API) for (gpgme_recipient_t r = res.recipients ; r ; r = r->next) { @@ -68,6 +71,10 @@ public: std::free(res.file_name); } res.file_name = 0; + if (res.symkey_algo) { + std::free(res.symkey_algo); + } + res.symkey_algo = 0; } _gpgme_op_decrypt_result res; ----------------------------------------------------------------------- Summary of changes: lang/cpp/src/decryptionresult.cpp | 7 +++++++ 1 file changed, 7 insertions(+) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 4 13:38:02 2018 From: cvs at cvs.gnupg.org (by Maximilian Krambach) Date: Wed, 04 Jul 2018 13:38:02 +0200 Subject: [git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-68-g1919fa4 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, javascript-binding has been updated via 1919fa41b6da4dfd4f69e776caa6e6b1883eb208 (commit) from 1105fc87a3bd3e1152aff578b7b84871558418e6 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 1919fa41b6da4dfd4f69e776caa6e6b1883eb208 Author: Maximilian Krambach Date: Wed Jul 4 13:38:54 2018 +0200 js: Add jsdoc, update webpack-cli dependency -- * package.json: - the old webpack-cli version depended on two packages with vulnerabilities, set to minimum version 3.0.8 to fix this (nodesecurity.io/advisories/157, nodesecurity.io/advisories/612) - added License identifier * README: Updated documentation * jsdoc.conf: Added a configuration file for jsdoc * some minor documentation changes, indentations diff --git a/lang/js/README b/lang/js/README index b597adb..86d2616 100644 --- a/lang/js/README +++ b/lang/js/README @@ -3,50 +3,80 @@ of gnupg in browsers, with the help of nativeMessaging. Installation ------------- -gpgmejs uses webpack, and thus depends on nodejs for building. Webpack can be -installed by running -`npm install webpack webpack-cli --save-dev`. +gpgmejs uses webpack, and thus depends on nodejs for building. All dependencies +will be installed (in a local subdirectory) with the command `npm install`. To create a current version of the package, the command is `npx webpack --config webpack.conf.js`. If you want a more debuggable (i.e. not minified) build, just change the mode in webpack.conf.js. -Demo WebExtension: -As soon as a bundled webpack is in dist/ -the gpgmejs folder can just be included in the extensions tab of the browser in -questions (extension debug mode needs to be active). For chrome, selecting the -folder is sufficient, for firefox, the manifest.json needs to be selected. +Demo and Test WebExtension: +--------------------------- + +The Demo Extension shows simple examples of the usage of gpgmejs. + +The BrowsertestExtension runs more intensive tests (using the mocha and chai +frameworks). Tests from BrowserTestExtension/tests will be run against the +gpgmejs.bundle.js itself. They aim to test the outward facing functionality +and API. + +Unittests as defined in ./unittests.js will be bundled in +gpgmejs_unittests.bundle.js, and test the separate components of gpgmejs, +which mostly are not exported. + +. The file `build_extension.sh` may serve as a pointer on how to +build and assemble these two Extensions and their dependencies. It can directly +be used in most linux systems. + +The resulting folders can just be included in the extensions tab of the browser +in questions (extension debug mode needs to be active). For chrome, selecting +the folder is sufficient, for firefox, the manifest.json needs to be selected. Please note that it is just for demonstration/debug purposes! +For the Extensions to successfully communicate with gpgme-json, a manifest file +is needed. + +- `~/.config/chromium/NativeMessagingHosts/gpgmejson.json` + In the browsers' nativeMessaging configuration folder a file 'gpgmejs.json' is needed, with the following content: -(The path to the native app gpgme-json may need adaption) - -Chromium: -~/.config/chromium/NativeMessagingHosts/gpgmejson.json - -{ - "name": "gpgmejson", - "description": "This is a test application for gpgmejs", - "path": "/usr/bin/gpgme-json", - "type": "stdio", - "allowed_origins": ["chrome-extension://ExtensionIdentifier/"] -} -The ExtensionIdentifier can be seen on the chrome://extensions page, and -changes on each reinstallation. Note the slashes in allowed_origins. - - -Firefox: -~/.mozilla/native-messaging-hosts/gpgmejson.json -{ - "name": "gpgmejson", - "description": "This is a test application for gpgmejs", - "path": "/usr/bin/gpgme-json", - "type": "stdio", - "allowed_extensions": ["ExtensionIdentifier at temporary-addon"] -} -The ExtensionIdentifier can be seen as Extension ID on the about:addons page if -addon-debugging is active. In firefox, the temporary addon is removed once -firefox exits, and the identifier will need to be changed more often. +- For Chrome/Chromium: + ``` + { + "name": "gpgmejson", + "description": "This is a test application for gpgmejs", + "path": "/usr/bin/gpgme-json", + "type": "stdio", + "allowed_origins": ["chrome-extension://ExtensionIdentifier/"] + } + ``` + The usual path for Linux is similar to: + `~/.config/chromium/NativeMessagingHosts/gpgmejson.json` for + For Windows, the path to the manifest needs to be placed in + `HKEY_LOCAL_MACHINE\SOFTWARE\Google\Chrome\NativeMessagingHosts\gpgmejson` + + - For firefox: + ``` + { + "name": "gpgmejson", + "description": "This is a test application for gpgmejs", + "path": "/usr/bin/gpgme-json", + "type": "stdio", + "allowed_extensions": ["ExtensionIdentifier at temporary-addon"] + } + ``` + + The ExtensionIdentifier can be seen as Extension ID on the about:addons page + if addon-debugging is active. In firefox, the temporary addon is removed once + firefox exits, and the identifier will need to be changed more often. + + The manifest for linux is usually placed at: + `~/.mozilla/native-messaging-hosts/gpgmejson.json` + +Documentation +------------- + +The documentation can be built by jsdoc. It currently uses the command +`./node_modules/.bin/jsdoc -c jsdoc.conf`. diff --git a/lang/js/README_testing b/lang/js/README_testing deleted file mode 100644 index b61ca1a..0000000 --- a/lang/js/README_testing +++ /dev/null @@ -1,14 +0,0 @@ -Test extension: - -The test extension contains tests with mocha and chai. It will be packed as an -extra extension (see build_extension.sh). - -Tests from BrowserTestExtension/tests will be run against the gpgmejs.bundle.js -itself. They aim to test the outward facing functionality and API. - -Unittests as defined in ./unittests.js will be bundled in -gpgmejs_unittests.bundle.js, and test the separate components of gpgmejs, -which mostly are not exported. - -The BrowserExtension can be installed the same way as the DemoExtension -(see README). \ No newline at end of file diff --git a/lang/js/jsdoc.conf b/lang/js/jsdoc.conf new file mode 100644 index 0000000..12ae35e --- /dev/null +++ b/lang/js/jsdoc.conf @@ -0,0 +1,24 @@ +{ + "tags": { + "allowUnknownTags": false, + "dictionaries": ["jsdoc"] + }, + "source": { + "include": ["./src"], + "includePattern": ".+\\.js(doc|x)?$", + "excludePattern": "(^|\\/|\\\\)_" + }, + "opts":{ + "destination": "./doc/", + "recurse": true + }, + "sourceType": "module", + "plugins": [], + "templates": { + "cleverLinks": false, + "monospaceLinks": false, + "default": { + "outputSourceFiles": true + } + } +} \ No newline at end of file diff --git a/lang/js/package.json b/lang/js/package.json index acf8911..54af298 100644 --- a/lang/js/package.json +++ b/lang/js/package.json @@ -6,11 +6,12 @@ "private": true, "keywords": [], "author": "", - "license": "", + "license": "LGPL-2.1+", "devDependencies": { "webpack": "^4.5.0", - "webpack-cli": "^2.0.14", + "webpack-cli": "^3.0.8", "chai": "^4.1.2", - "mocha": "^5.1.1" + "mocha": "^5.1.1", + "jsdoc": "^3.5.5" } } diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index f399b22..945932e 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -40,9 +40,10 @@ export class Connection{ * Retrieves the information about the backend. * @param {Boolean} details (optional) If set to false, the promise will * just return a connection status - * @returns {Promise} - * {String} The property 'gpgme': Version number of gpgme - * {Array} 'info' Further information about the backends. + * @returns {Promise} result + * @returns {String} result.gpgme Version number of gpgme + * @returns {Array} result.info Further information about the + * backends. * Example: * "protocol": "OpenPGP", * "fname": "/usr/bin/gpg", diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index 0d7643f..358757b 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -110,10 +110,10 @@ export class GPGME_Keyring { * contains a secret key. * @returns {Promise} * - * @async + * * TODO: getHasSecret always returns false at this moment, so this fucntion * still does not fully work as intended. - * + * * @async */ getDefaultKey() { let me = this; @@ -283,7 +283,7 @@ export class GPGME_Keyring { * @param {Date} expires (optional) Expiration date. If not set, expiration * will be set to 'never' * - * @returns{Promise} + * @return {Promise} */ generateKey(userId, algo = 'default', expires){ if ( diff --git a/lang/js/webpack.conf.js b/lang/js/webpack.conf.js index b2ad909..19f3bbd 100644 --- a/lang/js/webpack.conf.js +++ b/lang/js/webpack.conf.js @@ -19,17 +19,18 @@ * * This is the configuration file for building the gpgmejs-Library with webpack */ +/* global require, module, __dirname */ const path = require('path'); module.exports = { - entry: './src/index.js', - // mode: 'development', - mode: 'production', - output: { - path: path.resolve(__dirname, 'build'), - filename: 'gpgmejs.bundle.js', - libraryTarget: 'var', - libraryExport: 'default', - library: 'Gpgmejs' - } + entry: './src/index.js', + // mode: 'development', + mode: 'production', + output: { + path: path.resolve(__dirname, 'build'), + filename: 'gpgmejs.bundle.js', + libraryTarget: 'var', + libraryExport: 'default', + library: 'Gpgmejs' + } }; diff --git a/lang/js/webpack.conf_unittests.js b/lang/js/webpack.conf_unittests.js index 4b903be..c3c87f3 100644 --- a/lang/js/webpack.conf_unittests.js +++ b/lang/js/webpack.conf_unittests.js @@ -19,16 +19,18 @@ * * This is the configuration file for building the gpgmejs-Library with webpack */ +/* global require, module, __dirname */ + const path = require('path'); module.exports = { - entry: './unittests.js', - mode: 'production', - output: { - path: path.resolve(__dirname, 'build'), - filename: 'gpgmejs_unittests.bundle.js', - libraryTarget: 'var', - libraryExport: 'default', - library: 'Gpgmejs_test' - } + entry: './unittests.js', + mode: 'production', + output: { + path: path.resolve(__dirname, 'build'), + filename: 'gpgmejs_unittests.bundle.js', + libraryTarget: 'var', + libraryExport: 'default', + library: 'Gpgmejs_test' + } }; ----------------------------------------------------------------------- Summary of changes: lang/js/README | 102 ++++++++++++++++++++++++-------------- lang/js/README_testing | 14 ------ lang/js/jsdoc.conf | 24 +++++++++ lang/js/package.json | 7 +-- lang/js/src/Connection.js | 7 +-- lang/js/src/Keyring.js | 6 +-- lang/js/webpack.conf.js | 21 ++++---- lang/js/webpack.conf_unittests.js | 20 ++++---- 8 files changed, 123 insertions(+), 78 deletions(-) delete mode 100644 lang/js/README_testing create mode 100644 lang/js/jsdoc.conf hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 4 15:48:54 2018 From: cvs at cvs.gnupg.org (by Maximilian Krambach) Date: Wed, 04 Jul 2018 15:48:54 +0200 Subject: [git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-69-g10f2106 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, javascript-binding has been updated via 10f2106404f01e7bb369fc66a597875fb455cd27 (commit) from 1919fa41b6da4dfd4f69e776caa6e6b1883eb208 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 10f2106404f01e7bb369fc66a597875fb455cd27 Author: Maximilian Krambach Date: Wed Jul 4 15:46:45 2018 +0200 js: properly reject pgp message without signature -- * A verify at gpgme-json does not fail if there is a valid pgp message that does not include a signature. Instead, the answer will be devoid of signatures. In javascript, the SIG_NO_SIG error should be reported here, but wasn't. diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index c2a6b8b..f49361d 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -254,7 +254,7 @@ export class GpgME { } return new Promise(function(resolve, reject){ msg.post().then(function (message){ - if (!message.info.signatures){ + if (!message.info || !message.info.signatures){ reject(gpgme_error('SIG_NO_SIGS')); } else { let _result = collectSignatures(message.info.signatures); ----------------------------------------------------------------------- Summary of changes: lang/js/src/gpgmejs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 4 17:58:08 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Wed, 04 Jul 2018 17:58:08 +0200 Subject: [git] GnuPG - branch, STABLE-BRANCH-2-2, updated. gnupg-2.2.8-21-g063cf45 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, STABLE-BRANCH-2-2 has been updated via 063cf45c142f33815bc0f31d0fb3e1b25ca57b8c (commit) from cb6b925f94b42c91fe8a7ed8bb22d98984538efc (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 063cf45c142f33815bc0f31d0fb3e1b25ca57b8c Author: Andre Heinecke Date: Wed Jul 4 17:52:21 2018 +0200 po: Fix bug in german translation * po/de.po (decryption forced to fail!): Fix translation. -- The unmatched %s actually produced a crash on Windows. GnuPG-Bug-Id: T4053 GnuPG-Bug-Id: T4054 diff --git a/po/de.po b/po/de.po index 727b614..e9c08a4 100644 --- a/po/de.po +++ b/po/de.po @@ -4412,7 +4412,7 @@ msgid "Use the option '%s' to decrypt anyway.\n" msgstr "Mit der Option '%s' kann trotzdem entschl?sselt werden.\n" msgid "decryption forced to fail!\n" -msgstr "Entschl?sselung als fehlgeschlagen angesehen: %s\n" +msgstr "Entschl?sselungs-Fehler erzwungen!\n" msgid "decryption okay\n" msgstr "Entschl?sselung erfolgreich\n" ----------------------------------------------------------------------- Summary of changes: po/de.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 5 08:51:51 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Thu, 05 Jul 2018 08:51:51 +0200 Subject: [git] GPG-ERROR - branch, master, updated. libgpg-error-1.31-6-gfe2f8fc Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Error codes used by GnuPG et al.". The branch, master has been updated via fe2f8fca3114e3a5727fdbbc5e7ebc4e442d0401 (commit) from 043a91b8cd4bb71cb96086b51d6bc1b1a1821a41 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit fe2f8fca3114e3a5727fdbbc5e7ebc4e442d0401 Author: Andre Heinecke Date: Wed Jul 4 18:19:42 2018 +0200 core: Initialize values in estream_format * src/estream-printf.c (_gpgrt_estream_format): Make sure valuetable.value is inialized even on stack. -- This makes the behavior more consistent with the calloc'ed codepath for more then 8 variables. It also fixes a potential crash if there were unmatched format args provided. GnuPG-Bug-Id: T4054 diff --git a/src/estream-printf.c b/src/estream-printf.c index f1cbcde..eb6fa3a 100644 --- a/src/estream-printf.c +++ b/src/estream-printf.c @@ -1565,7 +1565,11 @@ _gpgrt_estream_format (estream_printf_out_t outfnc, else { for (validx=0; validx < DIM(valuetable_buffer); validx++) - valuetable[validx].vt = VALTYPE_UNSUPPORTED; + { + valuetable[validx].vt = VALTYPE_UNSUPPORTED; + memset (&valuetable[validx].value, 0, + sizeof valuetable[validx].value); + } } for (argidx=0; argidx < argspecs_len; argidx++) { ----------------------------------------------------------------------- Summary of changes: src/estream-printf.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) hooks/post-receive -- Error codes used by GnuPG et al. http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 5 09:21:18 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 05 Jul 2018 09:21:18 +0200 Subject: [git] GPG-ERROR - branch, master, updated. libgpg-error-1.31-8-g1ac63f6 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Error codes used by GnuPG et al.". The branch, master has been updated via 1ac63f630cbe1b558ebe20b746bbe4962117d36f (commit) via 8a72604dc44d36790669e6e591c12cc0b6e057bd (commit) from fe2f8fca3114e3a5727fdbbc5e7ebc4e442d0401 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 1ac63f630cbe1b558ebe20b746bbe4962117d36f Author: Werner Koch Date: Thu Jul 5 08:58:39 2018 +0200 Remove leftover debug output from gpg-error. * src/gpg-error.c (main): Remove a log_debug. -- Also a few typo fixes. Signed-off-by: Werner Koch diff --git a/src/argparse.c b/src/argparse.c index 2dab2ca..fecd3b5 100644 --- a/src/argparse.c +++ b/src/argparse.c @@ -1570,7 +1570,7 @@ _gpgrt_set_strusage (const char *(*f)(int) ) } -/* Set a function to write strings which is the used instead of +/* Set a function to write strings which is then used instead of * estream. The first arg of that function is MODE and the second the * STRING to write. A mode of 1 is used for writing to stdout and a * mode of 2 to write to stderr. Other modes are reserved and should diff --git a/src/gpg-error.c b/src/gpg-error.c index e0b0150..ade2bae 100644 --- a/src/gpg-error.c +++ b/src/gpg-error.c @@ -524,7 +524,6 @@ main (int argc, char *argv[]) } } gpgrt_argparse (NULL, &pargs, NULL); /* Free internal memory. */ - log_debug ("argc=%d listmode=%d\n", argc, listmode); if ((argc && listmode) || (!argc && !listmode)) gpgrt_usage (1); diff --git a/src/gpg-error.h.in b/src/gpg-error.h.in index 4c5ac38..8bcafcc 100644 --- a/src/gpg-error.h.in +++ b/src/gpg-error.h.in @@ -758,8 +758,8 @@ int gpgrt_write_hexstring (gpgrt_stream_t _GPGRT__RESTRICT stream, size_t gpgrt_fread (void *_GPGRT__RESTRICT ptr, size_t size, size_t nitems, gpgrt_stream_t _GPGRT__RESTRICT stream); -size_t gpgrt_fwrite (const void *_GPGRT__RESTRICT ptr, size_t size, size_t memb, - gpgrt_stream_t _GPGRT__RESTRICT stream); +size_t gpgrt_fwrite (const void *_GPGRT__RESTRICT ptr, size_t size, + size_t nitems, gpgrt_stream_t _GPGRT__RESTRICT stream); char *gpgrt_fgets (char *_GPGRT__RESTRICT s, int n, gpgrt_stream_t _GPGRT__RESTRICT stream); commit 8a72604dc44d36790669e6e591c12cc0b6e057bd Author: Yuri Chornoivan Date: Sat Apr 14 21:17:15 2018 +0300 po: Update Ukrainian translation. diff --git a/po/uk.po b/po/uk.po index 1a5f851..37ec7d1 100644 --- a/po/uk.po +++ b/po/uk.po @@ -2,12 +2,12 @@ # Copyright (C) 2012 Free Software Foundation, Inc. # This file is distributed under the same license as the libgpg-error package. # -# Yuri Chornoivan , 2012, 2014, 2015. +# Yuri Chornoivan , 2012, 2014, 2015, 2018. msgid "" msgstr "" "Project-Id-Version: libgpg-error 1.7\n" "Report-Msgid-Bugs-To: translations at gnupg.org\n" -"PO-Revision-Date: 2018-03-21 19:03+0100\n" +"PO-Revision-Date: 2018-04-14 21:07+0200\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian \n" "Language: uk\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Lokalize 1.5\n" +"X-Generator: Lokalize 2.0\n" msgid "Unspecified source" msgstr "????????? ???????" @@ -729,25 +729,19 @@ msgid "Bad octal character in S-expression" msgstr "?????????? ?????????? ?????? ? S-??????" msgid "All subkeys are expired or revoked" -msgstr "" +msgstr "????? ??? ???? ????????? ????????? ??? ?? ??????????" -#, fuzzy -#| msgid "Data not encrypted" msgid "Database is corrupted" -msgstr "???? ?? ???????????" +msgstr "???? ????? ??????????" msgid "Server indicated a failure" -msgstr "" +msgstr "?????? ?????????? ??? ???????" -#, fuzzy -#| msgid "Unknown name" msgid "No name" -msgstr "???????? ?????" +msgstr "????? ?????" -#, fuzzy -#| msgid "No public key" msgid "No key" -msgstr "????? ?????????? ?????" +msgstr "????? ?????" msgid "Legacy key" msgstr "?????????? ????" @@ -858,10 +852,10 @@ msgid "Invalid lock object" msgstr "??????????? ?????? ??????????" msgid "True" -msgstr "" +msgstr "???" msgid "False" -msgstr "" +msgstr "??" msgid "General IPC error" msgstr "???????? ??????? IPC" @@ -935,104 +929,76 @@ msgstr "??????? ? ????????? IPC" msgid "Unknown IPC inquire" msgstr "????????? ????? IPC" -#, fuzzy -#| msgid "No crypto engine" msgid "Crypto engine too old" -msgstr "????? ????? ??????????" +msgstr "????? ?????????? ? ????? ??????" msgid "Screen or window too small" -msgstr "" +msgstr "????? ??? ????? ? ????? ?????" msgid "Screen or window too large" -msgstr "" +msgstr "????? ??? ????? ? ????? ???????" msgid "Required environment variable not set" -msgstr "" +msgstr "?? ??????????? ????'??????? ??????? ??????????" -#, fuzzy #| msgid "Already exists (LDAP)" msgid "User ID already exists" -msgstr "??? ????? (LDAP)" +msgstr "????????????? ??????????? ??? ?????" -#, fuzzy #| msgid "Already exists (LDAP)" msgid "Name already exists" -msgstr "??? ????? (LDAP)" +msgstr "????? ??? ?????" -#, fuzzy -#| msgid "Duplicated value" msgid "Duplicated name" -msgstr "?????????? ????????" +msgstr "?????????? ?????" -#, fuzzy -#| msgid "Certificate too young" msgid "Object is too young" -msgstr "?????????? ? ????? ?????" +msgstr "??'??? ? ????? ?????" -#, fuzzy -#| msgid "Provided object is too short" msgid "Object is too old" -msgstr "??????? ?????? ? ????? ????????" +msgstr "??'??? ? ????? ??????" -#, fuzzy -#| msgid "Unknown name" msgid "Unknown flag" -msgstr "???????? ?????" +msgstr "????????? ?????????" -#, fuzzy -#| msgid "Invalid operation code" msgid "Invalid execution order" -msgstr "??????????? ??? ???" +msgstr "?????????? ????????????? ?????????" msgid "Already fetched" -msgstr "" +msgstr "??? ????????" msgid "Try again later" -msgstr "" +msgstr "????????? ?????? ???????" -#, fuzzy -#| msgid "Unknown name" msgid "Wrong name" -msgstr "???????? ?????" +msgstr "????????? ?????" msgid "System bug detected" -msgstr "" +msgstr "???????? ???? ? ???????" -#, fuzzy -#| msgid "Unknown system error" msgid "Unknown DNS error" -msgstr "???????? ???????? ???????" +msgstr "???????? ??????? DNS" -#, fuzzy -#| msgid "Invalid OID string" msgid "Invalid DNS section" -msgstr "??????????? ????? OID" +msgstr "??????????? ?????? DNS" -#, fuzzy -#| msgid "Invalid S-expression" msgid "Invalid textual address form" -msgstr "??????????? S-?????" +msgstr "??????????? ????????? ?????? ??????" -#, fuzzy -#| msgid "Missing issuer certificate" msgid "Missing DNS query packet" -msgstr "?? ???????? ??????????? ???????" +msgstr "?? ???????? ?????? ?????? ?? DNS" msgid "Missing DNS answer packet" -msgstr "" +msgstr "?? ???????? ?????? ?? ?????????? DNS" msgid "Connection closed in DNS" -msgstr "" +msgstr "?'??????? ??????? ? DNS" -#, fuzzy -#| msgid "Decryption failed" msgid "Verification failed in DNS" -msgstr "?????? ????????????? ??????? ???????" +msgstr "?? ???????? ????????? ?? DNS" -#, fuzzy -#| msgid "Timeout" msgid "DNS Timeout" -msgstr "??? ??????????" +msgstr "?????????? ??? ?????????? ?? DNS" msgid "General LDAP error" msgstr "???????? ??????? LDAP" @@ -1396,31 +1362,8 @@ msgid "invalid option \"%.50s\"\n" msgstr "??????????? ???????? ?%.50s?\n" msgid "Please report bugs to .\n" -msgstr "" +msgstr "???? ?????, ???????????? ??? ??????? ???: .\n" #, c-format msgid "warning: could not recognize %s\n" msgstr "????????????: ?? ??????? ?????????? %s\n" - -#~ msgid "Usage: %s GPG-ERROR [...]\n" -#~ msgstr "????????????: %s ???????-GPG [...]\n" - -#, fuzzy -#~| msgid "Resources exhausted" -#~ msgid "LCUP Resources exhausted" -#~ msgstr "????????? ???????" - -#, fuzzy -#~| msgid "Invalid data" -#~ msgid "LCUP Invalid data" -#~ msgstr "?????????? ????" - -#, fuzzy -#~| msgid "General error" -#~ msgid "LDAP Other general error" -#~ msgstr "???????? ???????" - -#, fuzzy -#~| msgid "dirmngr error" -#~ msgid "Encoding error" -#~ msgstr "??????? dirmngr" ----------------------------------------------------------------------- Summary of changes: po/uk.po | 125 +++++++++++++++-------------------------------------- src/argparse.c | 2 +- src/gpg-error.c | 1 - src/gpg-error.h.in | 4 +- 4 files changed, 37 insertions(+), 95 deletions(-) hooks/post-receive -- Error codes used by GnuPG et al. http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 5 09:49:24 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 05 Jul 2018 09:49:24 +0200 Subject: [git] GnuPG - branch, seckey-sync-work, created. gnupg-2.2.7-171-gfaf3c70 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, seckey-sync-work has been created at faf3c70c7715ba86eb56fdccc6cf831bf87b2ee0 (commit) - Log ----------------------------------------------------------------- commit faf3c70c7715ba86eb56fdccc6cf831bf87b2ee0 Author: Werner Koch Date: Thu Jul 5 09:40:35 2018 +0200 tools: Add experimental code for a pairing protocol * configure.ac (GNUPG_CACHE_DIR): New const. * tools/Makefile.am (libexec_PROGRAMS): Add gpg-pair-tool. (gpg_pair_tool_SOURCES, gpg_pair_tool_CFLAGS) (gpg_pair_tool_LDADD): New. * tools/gpg-pair-tool.c: New. -- This is a first try on a protocol to pair two devices so that they can agree on a shared secret to exchange secret keys. The idea is that if you want to sync your secret keys to another machine (e.g. from desktop to mobile) you have physical access to both devices and thus a pairing protocol allows to authenitcate the connection using a short string. See the source for a protocol description. How to test: $ gpg-pair-tool -va --homedir . --initiate >msg.commit $ gpg-pair-tool -va --homedir 2ndhome --respond \ msg.dhpart1 $ gpg-pair-tool -va --homedir . --respond \ msg.dhpart2 $ gpg-pair-tool -va --homedir 2ndhome --respond \ msg.confirm Now set the SAS as printed by the responder into SAS and run $ gpg-pair-tool -va --homedir . --respond --sas $SAS diff --git a/configure.ac b/configure.ac index 78a03c4..03f3af9 100644 --- a/configure.ac +++ b/configure.ac @@ -506,6 +506,7 @@ AH_BOTTOM([ #endif #define GNUPG_PRIVATE_KEYS_DIR "private-keys-v1.d" #define GNUPG_OPENPGP_REVOC_DIR "openpgp-revocs.d" +#define GNUPG_CACHE_DIR "cache.d" #define GNUPG_DEF_COPYRIGHT_LINE \ "Copyright (C) 2018 Free Software Foundation, Inc." diff --git a/tools/Makefile.am b/tools/Makefile.am index 0c828a7..a154276 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -51,7 +51,7 @@ else gpg_wks_server = endif -libexec_PROGRAMS = gpg-wks-client +libexec_PROGRAMS = gpg-wks-client gpg-pair-tool bin_PROGRAMS = gpgconf gpg-connect-agent ${symcryptrun} if !HAVE_W32_SYSTEM @@ -173,6 +173,14 @@ gpg_wks_client_LDADD = $(libcommon) \ $(LIBASSUAN_LIBS) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \ $(LIBINTL) $(LIBICONV) +gpg_pair_tool_SOURCES = \ + gpg-pair-tool.c + +gpg_pair_tool_CFLAGS = $(GPG_ERROR_CFLAGS) $(INCICONV) +gpg_pair_tool_LDADD = $(libcommon) \ + $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \ + $(LIBINTL) $(LIBICONV) + # Make sure that all libs are build before we use them. This is # important for things like make -j2. diff --git a/tools/gpg-pair-tool.c b/tools/gpg-pair-tool.c new file mode 100644 index 0000000..a86bd8e --- /dev/null +++ b/tools/gpg-pair-tool.c @@ -0,0 +1,2020 @@ +/* gpg-pair-tool.c - The tool to run the pairing protocol. + * Copyright (C) 2018 g10 Code GmbH + * + * 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 Lesser 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 . + */ + +/* Protocol: + * + * Initiator Responder + * | | + * | COMMIT | + * |-------------------->| + * | | + * | DHPART1 | + * |<--------------------| + * | | + * | DHPART2 | + * |-------------------->| + * | | + * | CONFIRM | + * |<--------------------| + * | | + * + * The initiator creates a keypar (PKi,SKi) and sends this COMMIT + * message to the responder: + * + * 7 byte Magic, value: "GPG-pa1" + * 1 byte MessageType, value 1 (COMMIT) + * 8 byte SessionId, value: 8 random bytes + * 1 byte Realm, value 1 + * 2 byte reserved, value 0 + * 5 byte ExpireTime, value: seconds since Epoch as an unsigned int. + * 32 byte Hash(PKi) + * + * The initiator also needs to locally store the sessionid, the realm, + * the expiration time, the keypair and a hash of the entire message + * sent. + * + * The responder checks that the received message has not expired and + * stores sessionid, realm, expiretime and the Hash(PKi). The + * Responder then creates and locally stores its own keypair (PKr,SKr) + * and sends the DHPART1 message back: + * + * 7 byte Magic, value: "GPG-pa1" + * 1 byte MessageType, value 2 (DHPART1) + * 8 byte SessionId from COMMIT message + * 32 byte PKr + * 32 byte Hash(Hash(COMMIT) || DHPART1[0..47]) + * + * Note that Hash(COMMIT) is the hash over the entire received COMMIT + * message. DHPART1[0..47] are the first 48 bytes of the created + * DHPART1 message. + * + * The Initiator receives the DHPART1 message and checks that the hash + * matches. Although this hash is easily malleable it is later in the + * protocol used to assert the integrity of all messages. The + * Initiator then computes the shared master secret from its SKi and + * the received PKr. Using this master secret several keys are + * derived: + * + * - HMACi-key using the label "GPG-pa1-HMACi-key". + * - SYMx-key using the label "GPG-pa1-SYMx-key" + * + * For details on the KDF see the implementation of the function kdf. + * The master secret is stored securily in the local state. The + * DHPART2 message is then created and send to the Responder: + * + * 7 byte Magic, value: "GPG-pa1" + * 1 byte MessageType, value 3 (DHPART2) + * 8 byte SessionId from COMMIT message + * 32 byte PKi + * 32 byte MAC(HMACi-key, Hash(DHPART1) || DHPART2[0..47] || SYMx-key) + * + * The Responder receives the DHPART2 message and checks that the hash + * of the received PKi matches the Hash(PKi) value as received earlier + * with the COMMIT message. The Responder now also computes the + * shared master secret from its SKr and the recived PKi and derives + * the keys: + * + * - HMACi-key using the label "GPG-pa1-HMACi-key". + * - HMACr-key using the label "GPG-pa1-HMACr-key". + * - SYMx-key using the label "GPG-pa1-SYMx-key" + * - SAS using the label "GPG-pa1-SAS" + * + * With these keys the MAC from the received DHPART2 message is + * checked. On success a SAS is displayed to the user and a CONFIRM + * message send back: + * + * 7 byte Magic, value: "GPG-pa1" + * 1 byte MessageType, value 4 (CONFIRM) + * 8 byte SessionId from COMMIT message + * 32 byte MAC(HMACr-key, Hash(DHPART2) || CONFIRM[0..15] || SYMx-key) + * + * The Initiator receives this CONFIRM message, gets the master shared + * secrey from its local state and derives the keys. It checks the + * the MAC in the received CONFIRM message and ask the user to enter + * the SAS as displayed by the responder. Iff the SAS matches the + * master key is flagged as confirmed and the Initiator may now use a + * derived key to send encrypted data to the Responder. + * + * In case the Responder also needs to send encrypted data we need to + * introduce another final message to tell the responder that the + * Initiator validated the SAS. + * + * TODO: Encrypt the state files using a key stored in gpg-agent's cache. + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/util.h" +#include "../common/status.h" +#include "../common/i18n.h" +#include "../common/sysutils.h" +#include "../common/init.h" +#include "../common/name-value.h" + + +/* Constants to identify the commands and options. */ +enum cmd_and_opt_values + { + aNull = 0, + + oQuiet = 'q', + oVerbose = 'v', + oOutput = 'o', + oArmor = 'a', + + aInitiate = 400, + aRespond = 401, + aGet = 402, + aCleanup = 403, + + oDebug = 500, + oStatusFD, + oHomedir, + oSAS, + + oDummy + }; + + +/* The list of commands and options. */ +static gpgrt_opt_t opts[] = { + ARGPARSE_group (300, ("@Commands:\n ")), + + ARGPARSE_c (aInitiate, "initiate", N_("initiate a pairing request")), + ARGPARSE_c (aRespond, "respond", N_("respond to a pairing request")), + ARGPARSE_c (aGet, "get", N_("return the keys")), + ARGPARSE_c (aCleanup, "cleanup", N_("remove expired states etc.")), + + ARGPARSE_group (301, ("@\nOptions:\n ")), + + ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")), + ARGPARSE_s_n (oQuiet, "quiet", N_("be somewhat more quiet")), + ARGPARSE_s_n (oArmor, "armor", N_("create ascii armored output")), + ARGPARSE_s_s (oSAS, "sas", N_("|SAS|the SAS as shown by the peer")), + ARGPARSE_s_s (oDebug, "debug", "@"), + ARGPARSE_s_s (oOutput, "output", N_("|FILE|write the request to FILE")), + ARGPARSE_s_i (oStatusFD, "status-fd", N_("|FD|write status info to this FD")), + + ARGPARSE_s_s (oHomedir, "homedir", "@"), + + ARGPARSE_end () +}; + + +/* We keep all global options in the structure OPT. */ +static struct +{ + int verbose; + unsigned int debug; + int quiet; + int armor; + const char *output; + estream_t statusfp; + unsigned int ttl; + const char *sas; +} opt; + + +/* Debug values and macros. */ +#define DBG_MESSAGE_VALUE 2 /* Debug the messages. */ +#define DBG_CRYPTO_VALUE 4 /* Debug low level crypto. */ +#define DBG_MEMORY_VALUE 32 /* Debug memory allocation stuff. */ + +#define DBG_MESSAGE (opt.debug & DBG_MESSAGE_VALUE) +#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE) + + +/* The list of supported debug flags. */ +static struct debug_flags_s debug_flags [] = + { + { DBG_MESSAGE_VALUE, "message" }, + { DBG_CRYPTO_VALUE , "crypto" }, + { DBG_MEMORY_VALUE , "memory" }, + { 0, NULL } + }; + + +/* The directory name below the cache dir to store paring states. */ +#define PAIRING_STATE_DIR "state" + +/* Message types. */ +#define MSG_TYPE_COMMIT 1 +#define MSG_TYPE_DHPART1 2 +#define MSG_TYPE_DHPART2 3 +#define MSG_TYPE_CONFIRM 4 + + +/* Realm values. */ +#define REALM_STANDARD 1 + + + + +/* Local prototypes. */ +static void wrong_args (const char *text) GPGRT_ATTR_NORETURN; +static void xnvc_set_printf (nvc_t nvc, const char *name, const char *format, + ...) GPGRT_ATTR_PRINTF(3,4); +static void *hash_data (void *result, size_t resultsize, + ...) GPGRT_ATTR_SENTINEL(0); +static void *hmac_data (void *result, size_t resultsize, + const unsigned char *key, size_t keylen, + ...) GPGRT_ATTR_SENTINEL(0); + + +static gpg_error_t command_initiate (void); +static gpg_error_t command_respond (void); +static gpg_error_t command_cleanup (void); +static gpg_error_t command_get (const char *sessionidstr); + + + + +/* Print usage information and provide strings for help. */ +static const char * +my_strusage( int level ) +{ + const char *p; + + switch (level) + { + case 9: p = "LGPL-2.1-or-later"; break; + case 11: p = "gpg-pair-tool"; break; + case 12: p = "@GNUPG@"; break; + case 13: p = VERSION; break; + case 14: p = GNUPG_DEF_COPYRIGHT_LINE; break; + case 17: p = PRINTABLE_OS_NAME; break; + case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break; + + case 1: + case 40: + p = ("Usage: gpg-pair-tool [command] [options] [args] (-h for help)"); + break; + case 41: + p = ("Syntax: gpg-pair-tool [command] [options] [args]\n" + "Client to run the pairing protocol\n"); + break; + + default: p = NULL; break; + } + return p; +} + + +static void +wrong_args (const char *text) +{ + es_fprintf (es_stderr, _("usage: %s [options] %s\n"), strusage (11), text); + exit (2); +} + + +/* Set the status FD. */ +static void +set_status_fd (int fd) +{ + static int last_fd = -1; + + if (fd != -1 && last_fd == fd) + return; + + if (opt.statusfp && opt.statusfp != es_stdout && opt.statusfp != es_stderr) + es_fclose (opt.statusfp); + opt.statusfp = NULL; + if (fd == -1) + return; + + if (fd == 1) + opt.statusfp = es_stdout; + else if (fd == 2) + opt.statusfp = es_stderr; + else + opt.statusfp = es_fdopen (fd, "w"); + if (!opt.statusfp) + { + log_fatal ("can't open fd %d for status output: %s\n", + fd, gpg_strerror (gpg_error_from_syserror ())); + } + last_fd = fd; +} + + +/* Write a status line with code NO followed by the outout of the + * printf style FORMAT. The caller needs to make sure that LFs and + * CRs are not printed. */ +static void +write_status (int no, const char *format, ...) +{ + va_list arg_ptr; + + if (!opt.statusfp) + return; /* Not enabled. */ + + es_fputs ("[GNUPG:] ", opt.statusfp); + es_fputs (get_status_string (no), opt.statusfp); + if (format) + { + es_putc (' ', opt.statusfp); + va_start (arg_ptr, format); + es_vfprintf (opt.statusfp, format, arg_ptr); + va_end (arg_ptr); + } + es_putc ('\n', opt.statusfp); +} + + + +/* gpg-pair-tool main. */ +int +main (int argc, char **argv) +{ + gpg_error_t err; + gpgrt_argparse_t pargs = { &argc, &argv }; + enum cmd_and_opt_values cmd = 0; + + opt.ttl = 8*3600; /* Default to 8 hours. */ + + gnupg_reopen_std ("gpg-pair-tool"); + gpgrt_set_strusage (my_strusage); + log_set_prefix ("gpg-pair-tool", GPGRT_LOG_WITH_PREFIX); + + /* Make sure that our subsystems are ready. */ + i18n_init(); + init_common_subsystems (&argc, &argv); + + /* Parse the command line. */ + while (gpgrt_argparse (NULL, &pargs, opts)) + { + switch (pargs.r_opt) + { + case oQuiet: opt.quiet = 1; break; + case oVerbose: opt.verbose++; break; + case oArmor: opt.armor = 1; break; + + case oDebug: + if (parse_debug_flag (pargs.r.ret_str, &opt.debug, debug_flags)) + { + pargs.r_opt = ARGPARSE_INVALID_ARG; + pargs.err = ARGPARSE_PRINT_ERROR; + } + break; + + case oOutput: + opt.output = pargs.r.ret_str; + break; + + case oStatusFD: + set_status_fd (translate_sys2libc_fd_int (pargs.r.ret_int, 1)); + break; + + case oHomedir: + gnupg_set_homedir (pargs.r.ret_str); + break; + + case oSAS: + opt.sas = pargs.r.ret_str; + break; + + case aInitiate: + case aRespond: + case aGet: + case aCleanup: + if (cmd && cmd != pargs.r_opt) + log_error (_("conflicting commands\n")); + else + cmd = pargs.r_opt; + break; + + default: pargs.err = ARGPARSE_PRINT_WARNING; break; + } + } + + /* Print a warning if an argument looks like an option. */ + if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN)) + { + int i; + + for (i=0; i < argc; i++) + if (argv[i][0] == '-' && argv[i][1] == '-') + log_info (("NOTE: '%s' is not considered an option\n"), argv[i]); + } + gpgrt_argparse (NULL, &pargs, NULL); /* Free internal memory. */ + + if (opt.sas) + { + if (strlen (opt.sas) != 11 + || !digitp (opt.sas+0) || !digitp (opt.sas+1) || !digitp (opt.sas+2) + || opt.sas[3] != '-' + || !digitp (opt.sas+4) || !digitp (opt.sas+5) || !digitp (opt.sas+6) + || opt.sas[7] != '-' + || !digitp (opt.sas+8) || !digitp (opt.sas+9) || !digitp (opt.sas+10)) + log_error ("invalid formatted SAS\n"); + } + + /* Stop if any error, inclduing ARGPARSE_PRINT_WARNING, occurred. */ + if (log_get_errorcount (0)) + exit (2); + + if (DBG_CRYPTO) + gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1|2); + + + /* Now run the requested command. */ + switch (cmd) + { + case aInitiate: + if (argc) + wrong_args ("--initiate"); + err = command_initiate (); + break; + + case aRespond: + if (argc) + wrong_args ("--respond"); + err = command_respond (); + break; + + case aGet: + if (argc > 1) + wrong_args ("--respond [sessionid]"); + err = command_get (argc? *argv:NULL); + break; + + case aCleanup: + if (argc) + wrong_args ("--cleanup"); + err = command_cleanup (); + break; + + default: + gpgrt_usage (1); + err = 0; + break; + } + + if (err) + write_status (STATUS_FAILURE, "- %u", err); + else if (log_get_errorcount (0)) + write_status (STATUS_FAILURE, "- %u", GPG_ERR_GENERAL); + else + write_status (STATUS_SUCCESS, NULL); + return log_get_errorcount (0)? 1:0; +} + + + +/* Wrapper around nvc_new which terminates in the error case. */ +static nvc_t +xnvc_new (void) +{ + nvc_t c = nvc_new (); + if (!c) + log_fatal ("error creating NVC object: %s\n", + gpg_strerror (gpg_error_from_syserror ())); + return c; +} + +/* Wrapper around nvc_set which terminates in the error case. */ +static void +xnvc_set (nvc_t nvc, const char *name, const char *value) +{ + gpg_error_t err = nvc_set (nvc, name, value); + if (err) + log_fatal ("error updating NVC object: %s\n", gpg_strerror (err)); +} + +/* Call vnc_set with (BUFFER, BUFLEN) converted to a hex string as + * value. Terminates in the error case. */ +static void +xnvc_set_hex (nvc_t nvc, const char *name, const void *buffer, size_t buflen) +{ + char *hex; + + hex = bin2hex (buffer, buflen, NULL); + if (!hex) + xoutofcore (); + strlwr (hex); + xnvc_set (nvc, name, hex); + xfree (hex); +} + +/* Call nvc_set with a value created from the string generated using + * the printf style FORMAT. Terminates in the error case. */ +static void +xnvc_set_printf (nvc_t nvc, const char *name, const char *format, ...) +{ + va_list arg_ptr; + char *buffer; + + va_start (arg_ptr, format); + if (gpgrt_vasprintf (&buffer, format, arg_ptr) < 0) + log_fatal ("estream_asprintf failed: %s\n", + gpg_strerror (gpg_error_from_syserror ())); + va_end (arg_ptr); + xnvc_set (nvc, name, buffer); + xfree (buffer); +} + + +/* Return the string for the first entry in NVC with NAME. If NAME is + * missing, an empty string is returned. The returned string is a + * pointer into NVC. */ +static const char * +xnvc_get_string (nvc_t nvc, const char *name) +{ + nve_t item; + + if (!nvc) + return ""; + item = nvc_lookup (nvc, name); + if (!item) + return ""; + return nve_value (item); +} + + + +/* Return a string for MSGTYPE. */ +const char * +msgtypestr (int msgtype) +{ + switch (msgtype) + { + case MSG_TYPE_COMMIT: return "Commit"; + case MSG_TYPE_DHPART1: return "DHPart1"; + case MSG_TYPE_DHPART2: return "DHPart2"; + case MSG_TYPE_CONFIRM: return "Confirm"; + } + return "?"; +} + + +/* Private to {get,set}_session_id(). */ +static struct { + int initialized; + unsigned char sessid[8]; +} session_id; + + +/* Return the 8 octet session. */ +static unsigned char * +get_session_id (void) +{ + if (!session_id.initialized) + { + session_id.initialized = 1; + gcry_create_nonce (session_id.sessid, sizeof session_id.sessid); + } + + return session_id.sessid; +} + +static void +set_session_id (const void *sessid, size_t len) +{ + log_assert (!session_id.initialized); + if (len > sizeof session_id.sessid) + len = sizeof session_id.sessid; + memcpy (session_id.sessid, sessid, len); + if (len < sizeof session_id.sessid) + memset (session_id.sessid+len, 0, sizeof session_id.sessid - len); + session_id.initialized = 1; +} + +/* Return a string with the hexified session id. */ +static const char * +get_session_id_hex (void) +{ + static char hexstr[16+1]; + + bin2hex (get_session_id (), 8, hexstr); + strlwr (hexstr); + return hexstr; +} + + +/* Return a fixed string with the directory used to store the state of + * pairings. On error a diagnostic is printed but the file name is + * returned anyway. It is expected that the expected failure of the + * following open is responsible for error handling. */ +static const char * +get_pairing_statedir (void) +{ + static char *fname; + gpg_error_t err = 0; + char *tmpstr; + struct stat statbuf; + + if (fname) + return fname; + + fname = make_filename (gnupg_homedir (), GNUPG_CACHE_DIR, NULL); + if (stat (fname, &statbuf) && errno == ENOENT) + { + if (gnupg_mkdir (fname, "-rwx")) + { + err = gpg_error_from_syserror (); + log_error (_("can't create directory '%s': %s\n"), + fname, gpg_strerror (err) ); + } + else if (!opt.quiet) + log_info (_("directory '%s' created\n"), fname); + } + + tmpstr = make_filename (fname, PAIRING_STATE_DIR, NULL); + xfree (fname); + fname = tmpstr; + if (stat (fname, &statbuf) && errno == ENOENT) + { + if (gnupg_mkdir (fname, "-rwx")) + { + if (!err) + { + err = gpg_error_from_syserror (); + log_error (_("can't create directory '%s': %s\n"), + fname, gpg_strerror (err) ); + } + } + else if (!opt.quiet) + log_info (_("directory '%s' created\n"), fname); + } + + return fname; +} + + +/* Open the pairing state file. SESSIONID is a 8 byte buffer with the + * session-id. If CREATE_FLAG is set the file is created and will + * always return a valid stream. If CREATE_FLAG is not set the file + * is opened for reading and writing. If the file does not exist NULL + * is return; in all other error cases the process is terminated. If + * R_FNAME is not NULL the name of the file is stored there and the + * caller needs to free it. */ +static estream_t +open_pairing_state (const unsigned char *sessionid, int create_flag, + char **r_fname) +{ + gpg_error_t err; + char *fname, *tmpstr; + estream_t fp; + + /* The filename is the session id with a "pa1" suffix. Note that + * the state dir may eventually be used for other purposes as well + * and thus the suffix identifies that the file belongs to this + * tool. We use lowercase file names for no real reason. */ + tmpstr = bin2hex (sessionid, 8, NULL); + if (!tmpstr) + xoutofcore (); + strlwr (tmpstr); + fname = xstrconcat (tmpstr, ".pa1", NULL); + xfree (tmpstr); + tmpstr = make_filename (get_pairing_statedir (), fname, NULL); + xfree (fname); + fname = tmpstr; + + fp = es_fopen (fname, create_flag? "wbx,mode=-rw": "rb+,mode=-rw"); + if (!fp) + { + err = gpg_error_from_syserror (); + if (create_flag) + { + /* We should always be able to create a file. Also we use a + * 64 bit session id, it is theoretically possible that such + * a session already exists. However, that is rare enough + * and thus the fatal error message should still be okay. */ + log_fatal ("can't create '%s': %s\n", fname, gpg_strerror (err)); + } + else if (gpg_err_code (err) == GPG_ERR_ENOENT) + { + /* That is an expected error; return NULL. */ + } + else + { + log_fatal ("can't open '%s': %s\n", fname, gpg_strerror (err)); + } + } + + if (r_fname) + *r_fname = fname; + else + xfree (fname); + + return fp; +} + + +/* Write the state to a possible new state file. */ +static void +write_state (nvc_t state, int create_flag) +{ + gpg_error_t err; + char *fname = NULL; + estream_t fp; + + fp = open_pairing_state (get_session_id (), create_flag, &fname); + log_assert (fp); + + err = nvc_write (state, fp); + if (err) + { + es_fclose (fp); + gnupg_remove (fname); + log_fatal ("error writing '%s': %s\n", fname, gpg_strerror (err)); + } + + /* If we did not create the file, we need to truncate the file. */ + if (!create_flag && ftruncate (es_fileno (fp), es_ftello (fp))) + { + err = gpg_error_from_syserror (); + log_fatal ("error truncating '%s': %s\n", fname, gpg_strerror (err)); + } + if (es_ferror (fp) || es_fclose (fp)) + { + err = gpg_error_from_syserror (); + es_fclose (fp); + gnupg_remove (fname); + log_fatal ("error writing '%s': %s\n", fname, gpg_strerror (err)); + } +} + + +/* Read the state into a newly allocated state object and store that + * at R_STATE. If no state is available GPG_ERR_NOT_FOUND is returned + * and as with all errors NULL is tored at R_STATE. SESSIONID is an + * input with the 8 session id. */ +static gpg_error_t +read_state (nvc_t *r_state) +{ + gpg_error_t err; + char *fname = NULL; + estream_t fp; + nvc_t state = NULL; + nve_t item; + const char *value; + unsigned long expire; + + *r_state = NULL; + + fp = open_pairing_state (get_session_id (), 0, &fname); + if (!fp) + return gpg_error (GPG_ERR_NOT_FOUND); + + err = nvc_parse (&state, NULL, fp); + if (err) + { + log_info ("failed to parse state file '%s': %s\n", + fname, gpg_strerror (err)); + goto leave; + } + + /* Check whether the state already expired. */ + item = nvc_lookup (state, "Expires:"); + if (!item) + { + log_info ("invalid state file '%s': %s\n", + fname, "field 'expire' not found"); + goto leave; + } + value = nve_value (item); + if (!value || !(expire = strtoul (value, NULL, 10))) + { + log_info ("invalid state file '%s': %s\n", + fname, "field 'expire' has an invalid value"); + goto leave; + } + if (expire <= gnupg_get_time ()) + { + es_fclose (fp); + fp = NULL; + if (gnupg_remove (fname)) + { + err = gpg_error_from_syserror (); + log_info ("failed to delete state file '%s': %s\n", + fname, gpg_strerror (err)); + } + else if (opt.verbose) + log_info ("state file '%s' deleted\n", fname); + err = gpg_error (GPG_ERR_NOT_FOUND); + goto leave; + } + + *r_state = state; + state = NULL; + + leave: + nvc_release (state); + es_fclose (fp); + return err; +} + + +/* Send (MSG,MSGLEN) to the output device. */ +static void +send_message (const unsigned char *msg, size_t msglen) +{ + gpg_error_t err; + + if (opt.verbose) + log_info ("session %s: sending %s message\n", + get_session_id_hex (), msgtypestr (msg[7])); + + if (DBG_MESSAGE) + log_printhex (msg, msglen, "send msg(%s):", msgtypestr (msg[7])); + + /* FIXME: For now only stdout. */ + if (opt.armor) + { + gpgrt_b64state_t state; + + state = gpgrt_b64enc_start (es_stdout, ""); + if (!state) + log_fatal ("error setting up base64 encoder: %s\n", + gpg_strerror (gpg_error_from_syserror ())); + err = gpgrt_b64enc_write (state, msg, msglen); + if (!err) + err = gpgrt_b64enc_finish (state); + if (err) + log_fatal ("error writing base64 to stdout: %s\n", gpg_strerror (err)); + } + else + { + if (es_fwrite (msg, msglen, 1, es_stdout) != 1) + log_fatal ("error writing to stdout: %s\n", + gpg_strerror (gpg_error_from_syserror ())); + } + es_fputc ('\n', es_stdout); +} + + +/* Read a message from stdin and store it at the address (R_MSG, + * R_MSGLEN). This function detects armoring and removes it. On + * error NULL is stored at R_MSG, a diagnostic printed and an error + * code returned. The returned message has a proper message type and + * an appropriate length. The message type is stored at R_MSGTYPE and + * if a state is availabale it is stored at R_STATE. */ +static gpg_error_t +read_message (unsigned char **r_msg, size_t *r_msglen, int *r_msgtype, + nvc_t *r_state) +{ + gpg_error_t err; + unsigned char msg[128]; /* max msg size is 80 but 107 with base64. */ + size_t msglen; + size_t reqlen; + + *r_msg = NULL; + *r_state = NULL; + + es_setvbuf (es_stdin, NULL, _IONBF, 0); + es_set_binary (es_stdin); + + if (es_read (es_stdin, msg, sizeof msg, &msglen)) + { + err = gpg_error_from_syserror (); + log_error ("error reading from message: %s\n", gpg_strerror (err)); + return err; + } + + if (msglen > 4 && !memcmp (msg, "R1BH", 4)) + { + /* This is base64 of the first 3 bytes. */ + gpgrt_b64state_t state = gpgrt_b64dec_start (NULL); + if (!state) + log_fatal ("error setting up base64 decoder: %s\n", + gpg_strerror (gpg_error_from_syserror ())); + err = gpgrt_b64dec_proc (state, msg, msglen, &msglen); + gpgrt_b64dec_finish (state); + if (err) + { + log_error ("error decoding message: %s\n", gpg_strerror (err)); + return err; + } + } + + if (msglen < 16 || memcmp (msg, "GPG-pa1", 7)) + { + log_error ("error parsing message: %s\n", + msglen? "invalid header":"empty message"); + return gpg_error (GPG_ERR_INV_RESPONSE); + } + switch (msg[7]) + { + case MSG_TYPE_COMMIT: reqlen = 56; break; + case MSG_TYPE_DHPART1: reqlen = 80; break; + case MSG_TYPE_DHPART2: reqlen = 80; break; + case MSG_TYPE_CONFIRM: reqlen = 48; break; + + default: + log_error ("error parsing message: %s\n", "invalid message type"); + return gpg_error (GPG_ERR_INV_RESPONSE); + } + if (msglen < reqlen) + { + log_error ("error parsing message: %s\n", "message too short"); + return gpg_error (GPG_ERR_INV_RESPONSE); + } + + if (DBG_MESSAGE) + log_printhex (msg, msglen, "recv msg(%s):", msgtypestr (msg[7])); + + /* Note that we ignore any garbage at the end of a message. */ + msglen = reqlen; + + set_session_id (msg+8, 8); + + if (opt.verbose) + log_info ("session %s: received %s message\n", + get_session_id_hex (), msgtypestr (msg[7])); + + /* Read the state. */ + err = read_state (r_state); + if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND) + return err; + + *r_msg = xmalloc (msglen); + memcpy (*r_msg, msg, msglen); + *r_msglen = msglen; + *r_msgtype = msg[7]; + return err; +} + + +/* Display the Short Authentication String (SAS). If WAIT is true the + * function waits until the user has entered the SAS as seen at the + * peer. + * + * To construct the SAS we take the 4 most significant octets of HASH, + * interpret them as a 32 bit big endian unsigned integer, divide that + * integer by 10^9 and take the remainder. The remainder is displayed + * as 3 groups of 3 decimal digits delimited by a hyphens. This gives + * a search space of close to 2^30 and is still easy to compare. + */ +static gpg_error_t +display_sas (const unsigned char *hash, size_t hashlen, int wait) +{ + gpg_error_t err; + unsigned long sas = 0; + char sasbuf[12]; + + log_assert (hashlen >= 4); + + sas |= (unsigned long)hash[20] << 24; + sas |= (unsigned long)hash[21] << 16; + sas |= (unsigned long)hash[22] << 8; + sas |= (unsigned long)hash[23]; + sas %= 1000000000ul; + snprintf (sasbuf, sizeof sasbuf, "%09lu", sas); + memmove (sasbuf+8, sasbuf+6, 3); + memmove (sasbuf+4, sasbuf+3, 3); + sasbuf[3] = sasbuf[7] = '-'; + sasbuf[11] = 0; + + if (wait) + log_info ("Please check the SAS:\n"); + else + log_info ("Please note the SAS:\n"); + log_info ("\n"); + log_info (" %s\n", sasbuf); + log_info ("\n"); + + if (wait) + { + if (!opt.sas || strcmp (sasbuf, opt.sas)) + err = gpg_error (GPG_ERR_NOT_CONFIRMED); + else + log_info ("SAS confirmed\n"); + } + + if (err) + log_info ("checking SAS failed: %s\n", gpg_strerror (err)); + return err; +} + + + +static gpg_error_t +create_dh_keypair (unsigned char *dh_secret, size_t dh_secret_len, + unsigned char *dh_public, size_t dh_public_len) +{ + gpg_error_t err; + gcry_sexp_t sexp; + gcry_sexp_t s_keypair; + gcry_buffer_t secret; + gcry_buffer_t public; + unsigned char publicbuf[33]; + + /* We need a temporary buffer for the public key. Check the length + * for the later memcpy. */ + if (dh_public_len < 32) + return gpg_error (GPG_ERR_BUFFER_TOO_SHORT); + + secret.size = dh_secret_len; + secret.data = dh_secret; + secret.off = 0; + public.size = sizeof publicbuf; + public.data = publicbuf; + public.off = 0; + + err = gcry_sexp_build (&sexp, NULL, + "(genkey(ecc(curve Curve25519)(flags djb-tweak)))"); + if (err) + return err; + err = gcry_pk_genkey (&s_keypair, sexp); + gcry_sexp_release (sexp); + if (err) + return err; + err = gcry_sexp_extract_param (s_keypair, "key-data!private-key", + "&dq", &secret, &public, NULL); + gcry_sexp_release (s_keypair); + if (err) + return err; + + /* Gcrypt prepends a 0x40 indicator - remove that. */ + if (public.len == 33) + { + public.len = 32; + memmove (public.data, publicbuf+1, 32); + } + memcpy (dh_public, public.data, public.len); + + if (DBG_CRYPTO) + { + log_printhex (secret.data, secret.len, "DH secret:"); + log_printhex (public.data, public.len, "DH public:"); + } + + return 0; +} + + +/* SHA256 the data given as varargs tuples of (const void*, size_t) + * and store the result in RESULT. The end of the list is indicated + * by a NULL element in a tuple. RESULTLEN gives the length of the + * RESULT buffer which must be at least 32. Note that the second item + * of the tuple is the length and it is a size_t. */ +static void * +hash_data (void *result, size_t resultsize, ...) +{ + va_list arg_ptr; + gpg_error_t err; + gcry_md_hd_t hd; + const void *data; + size_t datalen; + + log_assert (resultsize >= 32); + + err = gcry_md_open (&hd, GCRY_MD_SHA256, 0); + if (err) + log_fatal ("error creating a Hash handle: %s\n", gpg_strerror (err)); + /* log_printhex ("", 0, "Hash-256:"); */ + + va_start (arg_ptr, resultsize); + while ((data = va_arg (arg_ptr, const void *))) + { + datalen = va_arg (arg_ptr, size_t); + /* log_printhex (data, datalen, " data:"); */ + gcry_md_write (hd, data, datalen); + } + va_end (arg_ptr); + + memcpy (result, gcry_md_read (hd, 0), 32); + /* log_printhex (result, 32, " result:"); */ + + gcry_md_close (hd); + + return result; +} + + +/* HMAC-SHA256 the data given as varargs tuples of (const void*, + * size_t) using (KEYLEN,KEY) and store the result in RESULT. The end + * of the list is indicated by a NULL element in a tuple. RESULTLEN + * gives the length of the RESULT buffer which must be at least 32. + * Note that the second item of the tuple is the length and it is a + * size_t. */ +static void * +hmac_data (void *result, size_t resultsize, + const unsigned char *key, size_t keylen, ...) +{ + va_list arg_ptr; + gpg_error_t err; + gcry_mac_hd_t hd; + const void *data; + size_t datalen; + + log_assert (resultsize >= 32); + + err = gcry_mac_open (&hd, GCRY_MAC_HMAC_SHA256, 0, NULL); + if (err) + log_fatal ("error creating a MAC handle: %s\n", gpg_strerror (err)); + err = gcry_mac_setkey (hd, key, keylen); + if (err) + log_fatal ("error setting the MAC key: %s\n", gpg_strerror (err)); + /* log_printhex (key, keylen, "HMAC-key:"); */ + + va_start (arg_ptr, keylen); + while ((data = va_arg (arg_ptr, const void *))) + { + datalen = va_arg (arg_ptr, size_t); + /* log_printhex (data, datalen, " data:"); */ + err = gcry_mac_write (hd, data, datalen); + if (err) + log_fatal ("error writing to the MAC handle: %s\n", gpg_strerror (err)); + } + va_end (arg_ptr); + + err = gcry_mac_read (hd, result, &resultsize); + if (err || resultsize != 32) + log_fatal ("error reading MAC value: %s\n", gpg_strerror (err)); + /* log_printhex (result, resultsize, " result:"); */ + + gcry_mac_close (hd); + + return result; +} + + +/* Key derivation function: + * + * FIXME(doc) + */ +static void +kdf (unsigned char *result, size_t resultlen, + const unsigned char *master, size_t masterlen, + const unsigned char *sessionid, size_t sessionidlen, + const unsigned char *expire, size_t expirelen, + const char *label) +{ + log_assert (masterlen == 32 && sessionidlen == 8 && expirelen == 5); + log_assert (*label); + log_assert (resultlen == 32); + + hmac_data (result, resultlen, master, masterlen, + "\x00\x00\x00\x01", (size_t)4, /* Counter=1*/ + label, strlen (label) + 1, /* Label, 0x00 */ + sessionid, sessionidlen, /* Context */ + expire, expirelen, /* Context */ + "\x00\x00\x01\x00", (size_t)4, /* L=256 */ + NULL); +} + + +static gpg_error_t +compute_master_secret (unsigned char *master, size_t masterlen, + const unsigned char *sk_a, size_t sk_a_len, + const unsigned char *pk_b, size_t pk_b_len) +{ + gpg_error_t err; + gcry_sexp_t s_sk_a = NULL; + gcry_sexp_t s_pk_b = NULL; + gcry_sexp_t s_shared = NULL; + gcry_sexp_t s_tmp; + const char *s; + size_t n; + + log_assert (masterlen == 32); + + err = gcry_sexp_build (&s_sk_a, NULL, "%b", (int)sk_a_len, sk_a); + if (!err) + err = gcry_sexp_build (&s_pk_b, NULL, + "(public-key(ecdh(curve Curve25519)" + " (flags djb-tweak)(q%b)))", + (int)pk_b_len, pk_b); + if (err) + { + log_error ("error building S-expression: %s\n", gpg_strerror (err)); + goto leave; + } + + err = gcry_pk_encrypt (&s_shared, s_sk_a, s_pk_b); + if (err) + { + log_error ("error computing DH: %s\n", gpg_strerror (err)); + goto leave; + } + /* gcry_log_debugsxp ("sk_a", s_sk_a); */ + /* gcry_log_debugsxp ("pk_b", s_pk_b); */ + /* gcry_log_debugsxp ("shared", s_shared); */ + + s_tmp = gcry_sexp_find_token (s_shared, "s", 0); + if (!s_tmp || !(s = gcry_sexp_nth_data (s_tmp, 1, &n)) + || n != 33 || s[0] != 0x40) + { + err = gpg_error (GPG_ERR_INTERNAL); + log_error ("error computing DH: %s\n", gpg_strerror (err)); + goto leave; + } + memcpy (master, s+1, 32); + + + leave: + gcry_sexp_release (s_sk_a); + gcry_sexp_release (s_pk_b); + gcry_sexp_release (s_shared); + return err; +} + + +/* We are the Initiator: Create the commit message. This function + * sends the COMMIT message and writes STATE. */ +static gpg_error_t +make_msg_commit (nvc_t state) +{ + gpg_error_t err; + uint64_t now, expire; + unsigned char secret[32]; + unsigned char public[32]; + unsigned char *newmsg; + size_t newmsglen; + unsigned char tmphash[32]; + + err = create_dh_keypair (secret, sizeof secret, public, sizeof public ); + if (err) + log_error ("creating DH keypair failed: %s\n", gpg_strerror (err)); + + now = gnupg_get_time (); + expire = now + opt.ttl; + + newmsglen = 7+1+8+1+2+5+32; + newmsg = xmalloc (newmsglen); + memcpy (newmsg+0, "GPG-pa1", 7); + newmsg[7] = MSG_TYPE_COMMIT; + memcpy (newmsg+8, get_session_id (), 8); + newmsg[16] = REALM_STANDARD; + newmsg[17] = 0; + newmsg[18] = 0; + newmsg[19] = expire >> 32; + newmsg[20] = expire >> 24; + newmsg[21] = expire >> 16; + newmsg[22] = expire >> 8; + newmsg[23] = expire; + gcry_md_hash_buffer (GCRY_MD_SHA256, newmsg+24, public, 32); + + /* Create the state file. */ + xnvc_set (state, "State:", "Commit-sent"); + xnvc_set_printf (state, "Created:", "%llu", (unsigned long long)now); + xnvc_set_printf (state, "Expires:", "%llu", (unsigned long long)expire); + xnvc_set_hex (state, "DH-PKi:", public, 32); + xnvc_set_hex (state, "DH-SKi:", secret, 32); + gcry_md_hash_buffer (GCRY_MD_SHA256, tmphash, newmsg, newmsglen); + xnvc_set_hex (state, "Hash-Commit:", tmphash, 32); + + /* Write the state. Note that we need to create it. The state + * updating should in theory be done atomically with send_message. + * However, we can't assure that the message will actually be + * delivered and thus it doesn't matter whether we have an already + * update state when we later fail in send_message. */ + write_state (state, 1); + + /* Write the message. */ + send_message (newmsg, newmsglen); + + xfree (newmsg); + return err; +} + + +/* We are the Responder: Process a commit message in (MSG,MSGLEN) + * which has already been validated to have a correct header and + * message type. Sends the DHPart1 message and writes STATE. */ +static gpg_error_t +proc_msg_commit (nvc_t state, const unsigned char *msg, size_t msglen) +{ + gpg_error_t err; + uint64_t now, expire; + unsigned char tmphash[32]; + unsigned char secret[32]; + unsigned char public[32]; + unsigned char *newmsg = NULL; + size_t newmsglen; + + log_assert (msglen >= 56); + now = gnupg_get_time (); + + /* Check that the message has not expired. */ + expire = (uint64_t)msg[19] << 32; + expire |= (uint64_t)msg[20] << 24; + expire |= (uint64_t)msg[21] << 16; + expire |= (uint64_t)msg[22] << 8; + expire |= (uint64_t)msg[23]; + if (expire < now) + { + log_error ("received %s message is too old\n", + msgtypestr (MSG_TYPE_COMMIT)); + err = gpg_error (GPG_ERR_TOO_OLD); + goto leave; + } + + /* Create the response. */ + err = create_dh_keypair (secret, sizeof secret, public, sizeof public ); + if (err) + { + log_error ("creating DH keypair failed: %s\n", gpg_strerror (err)); + goto leave; + } + + newmsglen = 7+1+8+32+32; + newmsg = xmalloc (newmsglen); + memcpy (newmsg+0, "GPG-pa1", 7); + newmsg[7] = MSG_TYPE_DHPART1; + memcpy (newmsg+8, msg + 8, 8); /* SessionID. */ + memcpy (newmsg+16, public, 32); /* PKr */ + /* Hash(Hash(Commit) || DHPart1[0..47]) */ + gcry_md_hash_buffer (GCRY_MD_SHA256, tmphash, msg, msglen); + hash_data (newmsg+48, 32, + tmphash, sizeof tmphash, + newmsg, (size_t)48, + NULL); + + /* Update the state. */ + xnvc_set (state, "State:", "DHPart1-sent"); + xnvc_set_printf (state, "Created:", "%llu", (unsigned long long)now); + xnvc_set_printf (state, "Expires:", "%llu", (unsigned long long)expire); + xnvc_set_hex (state, "Hash-PKi:", msg+24, 32); + xnvc_set_hex (state, "DH-PKr:", public, 32); + xnvc_set_hex (state, "DH-SKr:", secret, 32); + gcry_md_hash_buffer (GCRY_MD_SHA256, tmphash, newmsg, newmsglen); + xnvc_set_hex (state, "Hash-DHPart1:", tmphash, 32); + + /* Write the state. Note that we need to create it. */ + write_state (state, 1); + + /* Write the message. */ + send_message (newmsg, newmsglen); + + leave: + xfree (newmsg); + return err; +} + + +/* We are the Initiator: Process a DHPART1 message in (MSG,MSGLEN) + * which has already been validated to have a correct header and + * message type. Sends the DHPart2 message and writes STATE. */ +static gpg_error_t +proc_msg_dhpart1 (nvc_t state, const unsigned char *msg, size_t msglen) +{ + gpg_error_t err; + unsigned char hash[32]; + unsigned char tmphash[32]; + unsigned char pki[32]; + unsigned char pkr[32]; + unsigned char ski[32]; + unsigned char master[32]; + uint64_t expire; + unsigned char expirebuf[5]; + unsigned char hmacikey[32]; + unsigned char symxkey[32]; + unsigned char *newmsg = NULL; + size_t newmsglen; + + log_assert (msglen >= 80); + + /* Check that the message includes the Hash(Commit). */ + if (hex2bin (xnvc_get_string (state, "Hash-Commit:"), hash, sizeof hash) < 0) + { + err = gpg_error (GPG_ERR_INV_VALUE); + log_error ("no or garbled 'Hash-Commit' in our state file\n"); + goto leave; + } + hash_data (tmphash, 32, + hash, sizeof hash, + msg, (size_t)48, + NULL); + if (memcmp (msg+48, tmphash, 32)) + { + err = gpg_error (GPG_ERR_BAD_DATA); + log_error ("manipulation of received %s message detected: %s\n", + msgtypestr (MSG_TYPE_DHPART1), "Bad Hash"); + goto leave; + } + /* Check that the received PKr is different from our PKi and copy + * PKr into PKR. */ + if (hex2bin (xnvc_get_string (state, "DH-PKi:"), pki, sizeof pki) < 0) + { + err = gpg_error (GPG_ERR_INV_VALUE); + log_error ("no or garbled 'DH-PKi' in our state file\n"); + goto leave; + } + if (!memcmp (msg+16, pki, 32)) + { + /* This can only happen if the state file leaked to the + * responder. */ + err = gpg_error (GPG_ERR_BAD_DATA); + log_error ("received our own public key PKi instead of PKr\n"); + goto leave; + } + memcpy (pkr, msg+16, 32); + + /* Put the expire value into a buffer. */ + expire = string_to_u64 (xnvc_get_string (state, "Expires:")); + if (!expire) + { + err = gpg_error (GPG_ERR_INV_VALUE); + log_error ("no 'Expire' in our state file\n"); + goto leave; + } + expirebuf[0] = expire >> 32; + expirebuf[1] = expire >> 24; + expirebuf[2] = expire >> 16; + expirebuf[3] = expire >> 8; + expirebuf[4] = expire; + + /* Get our secret from the state. */ + if (hex2bin (xnvc_get_string (state, "DH-SKi:"), ski, sizeof ski) < 0) + { + err = gpg_error (GPG_ERR_INV_VALUE); + log_error ("no or garbled 'DH-SKi' in our state file\n"); + goto leave; + } + + /* Compute the shared secrets. */ + err = compute_master_secret (master, sizeof master, + ski, sizeof ski, pkr, sizeof pkr); + if (err) + { + log_error ("creating DH keypair failed: %s\n", gpg_strerror (err)); + goto leave; + } + + kdf (hmacikey, sizeof hmacikey, + master, sizeof master, msg+8, 8, expirebuf, sizeof expirebuf, + "GPG-pa1-HMACi-key"); + kdf (symxkey, sizeof symxkey, + master, sizeof master, msg+8, 8, expirebuf, sizeof expirebuf, + "GPG-pa1-SYMx-key"); + + + /* Create the response. */ + newmsglen = 7+1+8+32+32; + newmsg = xmalloc (newmsglen); + memcpy (newmsg+0, "GPG-pa1", 7); + newmsg[7] = MSG_TYPE_DHPART2; + memcpy (newmsg+8, msg + 8, 8); /* SessionID. */ + memcpy (newmsg+16, pki, 32); /* PKi */ + /* MAC(HMACi-key, Hash(DHPART1) || DHPART2[0..47] || SYMx-key) */ + gcry_md_hash_buffer (GCRY_MD_SHA256, tmphash, msg, msglen); + hmac_data (newmsg+48, 32, hmacikey, sizeof hmacikey, + tmphash, sizeof tmphash, + newmsg, (size_t)48, + symxkey, sizeof symxkey, + NULL); + + /* Update the state. */ + xnvc_set (state, "State:", "DHPart2-sent"); + xnvc_set_hex (state, "DH-Master:", master, sizeof master); + gcry_md_hash_buffer (GCRY_MD_SHA256, tmphash, newmsg, newmsglen); + xnvc_set_hex (state, "Hash-DHPart2:", tmphash, 32); + + /* Write the state. */ + write_state (state, 0); + + /* Write the message. */ + send_message (newmsg, newmsglen); + + leave: + xfree (newmsg); + return err; +} + + +/* We are the Responder: Process a DHPART2 message in (MSG,MSGLEN) + * which has already been validated to have a correct header and + * message type. Sends the CONFIRM message and writes STATE. */ +static gpg_error_t +proc_msg_dhpart2 (nvc_t state, const unsigned char *msg, size_t msglen) +{ + gpg_error_t err; + unsigned char hash[32]; + unsigned char tmphash[32]; + uint64_t expire; + unsigned char expirebuf[5]; + unsigned char pki[32]; + unsigned char pkr[32]; + unsigned char skr[32]; + unsigned char master[32]; + unsigned char hmacikey[32]; + unsigned char hmacrkey[32]; + unsigned char symxkey[32]; + unsigned char sas[32]; + unsigned char *newmsg = NULL; + size_t newmsglen; + + log_assert (msglen >= 80); + + /* Check that the PKi in the message matches the Hash(Pki) received + * with the Commit message. */ + memcpy (pki, msg + 16, 32); + gcry_md_hash_buffer (GCRY_MD_SHA256, hash, pki, 32); + if (hex2bin (xnvc_get_string (state, "Hash-PKi:"), + tmphash, sizeof tmphash) < 0) + { + err = gpg_error (GPG_ERR_INV_VALUE); + log_error ("no or garbled 'Hash-PKi' in our state file\n"); + goto leave; + } + if (memcmp (hash, tmphash, 32)) + { + err = gpg_error (GPG_ERR_BAD_DATA); + log_error ("Initiator sent a different key in %s than announced in %s\n", + msgtypestr (MSG_TYPE_DHPART2), + msgtypestr (MSG_TYPE_COMMIT)); + goto leave; + } + /* Check that the received PKi is different from our PKr. */ + if (hex2bin (xnvc_get_string (state, "DH-PKr:"), pkr, sizeof pkr) < 0) + { + err = gpg_error (GPG_ERR_INV_VALUE); + log_error ("no or garbled 'DH-PKr' in our state file\n"); + goto leave; + } + if (!memcmp (pkr, pki, 32)) + { + err = gpg_error (GPG_ERR_BAD_DATA); + log_error ("Initiator sent our own PKr back\n"); + goto leave; + } + + /* Put the expire value into a buffer. */ + expire = string_to_u64 (xnvc_get_string (state, "Expires:")); + if (!expire) + { + err = gpg_error (GPG_ERR_INV_VALUE); + log_error ("no 'Expire' in our state file\n"); + goto leave; + } + expirebuf[0] = expire >> 32; + expirebuf[1] = expire >> 24; + expirebuf[2] = expire >> 16; + expirebuf[3] = expire >> 8; + expirebuf[4] = expire; + + /* Get our secret from the state. */ + if (hex2bin (xnvc_get_string (state, "DH-SKr:"), skr, sizeof skr) < 0) + { + err = gpg_error (GPG_ERR_INV_VALUE); + log_error ("no or garbled 'DH-SKr' in our state file\n"); + goto leave; + } + + /* Compute the shared secrets. */ + err = compute_master_secret (master, sizeof master, + skr, sizeof skr, pki, sizeof pki); + if (err) + { + log_error ("creating DH keypair failed: %s\n", gpg_strerror (err)); + goto leave; + } + + kdf (hmacikey, sizeof hmacikey, + master, sizeof master, msg+8, 8, expirebuf, sizeof expirebuf, + "GPG-pa1-HMACi-key"); + kdf (hmacrkey, sizeof hmacrkey, + master, sizeof master, msg+8, 8, expirebuf, sizeof expirebuf, + "GPG-pa1-HMACr-key"); + kdf (symxkey, sizeof symxkey, + master, sizeof master, msg+8, 8, expirebuf, sizeof expirebuf, + "GPG-pa1-SYMx-key"); + kdf (sas, sizeof sas, + master, sizeof master, msg+8, 8, expirebuf, sizeof expirebuf, + "GPG-pa1-SAS"); + + /* Check the MAC from the message which is + * MAC(HMACi-key, Hash(DHPART1) || DHPART2[0..47] || SYMx-key). + * For that we need to fetch the stored hash from the state. */ + if (hex2bin (xnvc_get_string (state, "Hash-DHPart1:"), + tmphash, sizeof tmphash) < 0) + { + err = gpg_error (GPG_ERR_INV_VALUE); + log_error ("no or garbled 'Hash-DHPart1' in our state file\n"); + goto leave; + } + hmac_data (hash, 32, hmacikey, sizeof hmacikey, + tmphash, sizeof tmphash, + msg, 48, + symxkey, sizeof symxkey, + NULL); + if (memcmp (msg+48, hash, 32)) + { + err = gpg_error (GPG_ERR_BAD_DATA); + log_error ("manipulation of received %s message detected: %s\n", + msgtypestr (MSG_TYPE_DHPART2), "Bad MAC"); + goto leave; + } + + /* Create the response. */ + newmsglen = 7+1+8+32; + newmsg = xmalloc (newmsglen); + memcpy (newmsg+0, "GPG-pa1", 7); + newmsg[7] = MSG_TYPE_CONFIRM; + memcpy (newmsg+8, msg + 8, 8); /* SessionID. */ + /* MAC(HMACr-key, Hash(DHPART2) || CONFIRM[0..15] || SYMx-key) */ + gcry_md_hash_buffer (GCRY_MD_SHA256, tmphash, msg, msglen); + hmac_data (newmsg+16, 32, hmacrkey, sizeof hmacrkey, + tmphash, sizeof tmphash, + newmsg, (size_t)16, + symxkey, sizeof symxkey, + NULL); + + /* Update the state. */ + xnvc_set (state, "State:", "Confirm-sent"); + xnvc_set_hex (state, "DH-Master:", master, sizeof master); + + /* Write the state. */ + write_state (state, 0); + + /* Write the message. */ + send_message (newmsg, newmsglen); + + display_sas (sas, sizeof sas, 0); + + + leave: + xfree (newmsg); + return err; +} + + +/* We are the Initiator: Process a CONFIRM message in (MSG,MSGLEN) + * which has already been validated to have a correct header and + * message type. Does not send anything back. */ +static gpg_error_t +proc_msg_confirm (nvc_t state, const unsigned char *msg, size_t msglen) +{ + gpg_error_t err; + unsigned char hash[32]; + unsigned char tmphash[32]; + unsigned char master[32]; + uint64_t expire; + unsigned char expirebuf[5]; + unsigned char hmacrkey[32]; + unsigned char symxkey[32]; + unsigned char sas[32]; + + log_assert (msglen >= 48); + + /* Put the expire value into a buffer. */ + expire = string_to_u64 (xnvc_get_string (state, "Expires:")); + if (!expire) + { + err = gpg_error (GPG_ERR_INV_VALUE); + log_error ("no 'Expire' in our state file\n"); + goto leave; + } + expirebuf[0] = expire >> 32; + expirebuf[1] = expire >> 24; + expirebuf[2] = expire >> 16; + expirebuf[3] = expire >> 8; + expirebuf[4] = expire; + + /* Get the master secret. */ + if (hex2bin (xnvc_get_string (state, "DH-Master:"),master,sizeof master) < 0) + { + err = gpg_error (GPG_ERR_INV_VALUE); + log_error ("no or garbled 'DH-Master' in our state file\n"); + goto leave; + } + + kdf (hmacrkey, sizeof hmacrkey, + master, sizeof master, msg+8, 8, expirebuf, sizeof expirebuf, + "GPG-pa1-HMACr-key"); + kdf (symxkey, sizeof symxkey, + master, sizeof master, msg+8, 8, expirebuf, sizeof expirebuf, + "GPG-pa1-SYMx-key"); + kdf (sas, sizeof sas, + master, sizeof master, msg+8, 8, expirebuf, sizeof expirebuf, + "GPG-pa1-SAS"); + + /* Check the MAC from the message which is */ + /* MAC(HMACr-key, Hash(DHPART2) || CONFIRM[0..15] || SYMx-key). */ + if (hex2bin (xnvc_get_string (state, "Hash-DHPart2:"), + tmphash, sizeof tmphash) < 0) + { + err = gpg_error (GPG_ERR_INV_VALUE); + log_error ("no or garbled 'Hash-DHPart2' in our state file\n"); + goto leave; + } + hmac_data (hash, 32, hmacrkey, sizeof hmacrkey, + tmphash, sizeof tmphash, + msg, (size_t)16, + symxkey, sizeof symxkey, + NULL); + if (!memcmp (msg+48, hash, 32)) + { + err = gpg_error (GPG_ERR_BAD_DATA); + log_error ("manipulation of received %s message detected: %s\n", + msgtypestr (MSG_TYPE_CONFIRM), "Bad MAC"); + goto leave; + } + + + err = display_sas (sas, sizeof sas, 1); + if (err) + goto leave; + + /* Update the state. */ + xnvc_set (state, "State:", "Confirmed"); + + /* Write the state. */ + write_state (state, 0); + + leave: + return err; +} + + + +/* Expire old state files. This loops over all state files and remove + * those which are expired. */ +static void +expire_old_states (void) +{ + gpg_error_t err = 0; + const char *dirname; + DIR *dir = NULL; + struct dirent *dir_entry; + char *fname = NULL; + estream_t fp = NULL; + nvc_t nvc = NULL; + nve_t item; + const char *value; + unsigned long expire; + unsigned long now = gnupg_get_time (); + + dirname = get_pairing_statedir (); + dir = opendir (dirname); + if (!dir) + { + err = gpg_error_from_syserror (); + goto leave; + } + + while ((dir_entry = readdir (dir))) + { + if (strlen (dir_entry->d_name) != 16+4 + || strcmp (dir_entry->d_name + 16, ".pa1")) + continue; + + xfree (fname); + fname = make_filename (dirname, dir_entry->d_name, NULL); + es_fclose (fp); + fp = es_fopen (fname, "rb"); + if (!fp) + { + err = gpg_error_from_syserror (); + if (gpg_err_code (err) != GPG_ERR_ENOENT) + log_info ("failed to open state file '%s': %s\n", + fname, gpg_strerror (err)); + continue; + } + nvc_release (nvc); + + /* NB.: The following is similar to code in read_state. */ + err = nvc_parse (&nvc, NULL, fp); + if (err) + { + log_info ("failed to parse state file '%s': %s\n", + fname, gpg_strerror (err)); + continue; /* Skip */ + } + item = nvc_lookup (nvc, "Expires:"); + if (!item) + { + log_info ("invalid state file '%s': %s\n", + fname, "field 'expire' not found"); + continue; /* Skip */ + } + value = nve_value (item); + if (!value || !(expire = strtoul (value, NULL, 10))) + { + log_info ("invalid state file '%s': %s\n", + fname, "field 'expire' has an invalid value"); + continue; /* Skip */ + } + + if (expire <= now) + { + es_fclose (fp); + fp = NULL; + if (gnupg_remove (fname)) + { + err = gpg_error_from_syserror (); + log_info ("failed to delete state file '%s': %s\n", + fname, gpg_strerror (err)); + } + else if (opt.verbose) + log_info ("state file '%s' deleted\n", fname); + } + } + + leave: + if (err) + log_error ("expiring old states in '%s' failed: %s\n", + dirname, gpg_strerror (err)); + if (dir) + closedir (dir); + es_fclose (fp); + xfree (fname); +} + + + +/* Initiate a pairing. The output needs to be conveyed to the + * peer */ +static gpg_error_t +command_initiate (void) +{ + gpg_error_t err; + nvc_t state; + + state = xnvc_new (); + xnvc_set (state, "Version:", "GPG-pa1"); + xnvc_set_hex (state, "Session:", get_session_id (), 8); + xnvc_set (state, "Role:", "Initiator"); + + err = make_msg_commit (state); + + nvc_release (state); + return err; +} + + + +/* Helper for command_respond(). */ +static gpg_error_t +expect_state (int msgtype, const char *statestr, const char *expected) +{ + if (strcmp (statestr, expected)) + { + log_error ("received %s message in %s state (should be %s)\n", + msgtypestr (msgtype), statestr, expected); + return gpg_error (GPG_ERR_INV_RESPONSE); + } + return 0; +} + +/* Respond to a pairing intiation. This is used by the peer and later + * by the original responder. Depending on the state the output needs + * to be conveyed to the peer. */ +static gpg_error_t +command_respond (void) +{ + gpg_error_t err; + unsigned char *msg; + size_t msglen; + int msgtype; + nvc_t state; + const char *rolestr; + const char *statestr; + + err = read_message (&msg, &msglen, &msgtype, &state); + if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND) + goto leave; + rolestr = xnvc_get_string (state, "Role:"); + statestr = xnvc_get_string (state, "State:"); + if (DBG_MESSAGE) + { + if (!state) + log_debug ("no state available\n"); + else + log_debug ("we are %s, our current state is %s\n", rolestr, statestr); + log_debug ("got message of type %s (%d)\n", + msgtypestr (msgtype), msgtype); + } + + if (!state) + { + if (msgtype == MSG_TYPE_COMMIT) + { + state = xnvc_new (); + xnvc_set (state, "Version:", "GPG-pa1"); + xnvc_set_hex (state, "Session:", get_session_id (), 8); + xnvc_set (state, "Role:", "Responder"); + err = proc_msg_commit (state, msg, msglen); + } + else + { + log_error ("%s message expected but got %s\n", + msgtypestr (MSG_TYPE_COMMIT), msgtypestr (msgtype)); + if (msgtype == MSG_TYPE_DHPART1) + log_info ("the pairing probably took too long and timed out\n"); + err = gpg_error (GPG_ERR_INV_RESPONSE); + goto leave; + } + } + else if (!strcmp (rolestr, "Initiator")) + { + if (msgtype == MSG_TYPE_DHPART1) + { + if (!(err = expect_state (msgtype, statestr, "Commit-sent"))) + err = proc_msg_dhpart1 (state, msg, msglen); + } + else if (msgtype == MSG_TYPE_CONFIRM) + { + if (!(err = expect_state (msgtype, statestr, "DHPart2-sent"))) + err = proc_msg_confirm (state, msg, msglen); + } + else + { + log_error ("%s message not expected by Initiator\n", + msgtypestr (msgtype)); + err = gpg_error (GPG_ERR_INV_RESPONSE); + goto leave; + } + } + else if (!strcmp (rolestr, "Responder")) + { + if (msgtype == MSG_TYPE_DHPART2) + { + if (!(err = expect_state (msgtype, statestr, "DHPart1-sent"))) + err = proc_msg_dhpart2 (state, msg, msglen); + } + else + { + log_error ("%s message not expected by Responder\n", + msgtypestr (msgtype)); + err = gpg_error (GPG_ERR_INV_RESPONSE); + goto leave; + } + } + else + log_fatal ("invalid role '%s' in state file\n", rolestr); + + + leave: + xfree (msg); + nvc_release (state); + return err; +} + + + +/* Return the keys for SESSIONIDSTR or the last one if it is NULL. + * Two keys are returned: The first is the one for sending encrypted + * data and the second one for decrypting received data. The keys are + * always returned hex encoded and both are terminated by a LF. */ +static gpg_error_t +command_get (const char *sessionidstr) +{ + gpg_error_t err; + unsigned char sessid[8]; + nvc_t state; + + if (!sessionidstr) + { + log_error ("calling without session-id is not yet implemented\n"); + err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); + goto leave; + } + if (hex2bin (sessionidstr, sessid, sizeof sessid) < 0) + { + err = gpg_error (GPG_ERR_INV_VALUE); + log_error ("invalid session id given\n"); + goto leave; + } + set_session_id (sessid, sizeof sessid); + err = read_state (&state); + if (err) + { + log_error ("reading state of session %s failed: %s\n", + sessionidstr, gpg_strerror (err)); + goto leave; + } + + leave: + return err; +} + + + +/* Cleanup command. */ +static gpg_error_t +command_cleanup (void) +{ + expire_old_states (); + return 0; +} ----------------------------------------------------------------------- hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 5 09:50:19 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 05 Jul 2018 09:50:19 +0200 Subject: [git] GnuPG - branch, master, updated. gnupg-2.2.7-171-g9ea9b9d Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 9ea9b9db7e1b3e6a84104a2be48d492f12c6316c (commit) from 01cd66f9faf1623833e6afac84164de5a136ecff (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 9ea9b9db7e1b3e6a84104a2be48d492f12c6316c Author: Werner Koch Date: Thu Jul 5 09:42:06 2018 +0200 doc: Typo fix in a comment. -- diff --git a/g10/keygen.c b/g10/keygen.c index 9e9cead..fbead10 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -3293,7 +3293,7 @@ parse_key_parameter_string (const char *string, int part, * part consider this to be the subkey algo. In case a * SUGGESTED_USE has been given and the usage of the secondary * part does not match SUGGESTED_USE try again using the primary - * part. Noet thar when falling back to the primary key we need + * part. Note that when falling back to the primary key we need * to force clearing the cert usage. */ if (secondary) { ----------------------------------------------------------------------- Summary of changes: g10/keygen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 5 11:32:08 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Thu, 05 Jul 2018 11:32:08 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-81-g66c2a99 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 66c2a99422dd9a52d8342165ed1d033c4f29b9e0 (commit) via 629afebe5017db97f2a318f6878fe1f9d3e60189 (commit) via a2458806f8bf04b66795e1dde765b42fe1ef6797 (commit) from 7d65dc2a5c4f32139a1b9b1f0bd375f7ab1c58f6 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 66c2a99422dd9a52d8342165ed1d033c4f29b9e0 Author: Andre Heinecke Date: Thu Jul 5 11:28:08 2018 +0200 qt: Handle OpenPGP Diagnostic log * lang/qt/src/threadedjobmixin.cpp (_detail::audit_log_as_html): Handle OpenPGP audit log differently. diff --git a/lang/qt/src/threadedjobmixin.cpp b/lang/qt/src/threadedjobmixin.cpp index 74755c5..8fed77c 100644 --- a/lang/qt/src/threadedjobmixin.cpp +++ b/lang/qt/src/threadedjobmixin.cpp @@ -53,7 +53,16 @@ using namespace QGpgME; using namespace GpgME; -static const unsigned int GetAuditLogFlags = Context::AuditLogWithHelp | Context::HtmlAuditLog; +static QString markupDiagnostics(const QString &data) +{ + // First ensure that we don't have html in the diag. + QString ret = QStringLiteral("
    %1
    ").arg(data.toHtmlEscaped()); + + return ret; +} + +static const unsigned int CMSAuditLogFlags = Context::AuditLogWithHelp | Context::HtmlAuditLog; +static const unsigned int OpenPGPAuditLogFlags = Context::DiagnosticAuditLog; QString _detail::audit_log_as_html(Context *ctx, GpgME::Error &err) { @@ -61,11 +70,24 @@ QString _detail::audit_log_as_html(Context *ctx, GpgME::Error &err) QGpgME::QByteArrayDataProvider dp; Data data(&dp); assert(!data.isNull()); - if ((err = ctx->lastError()) || (err = ctx->getAuditLog(data, GetAuditLogFlags))) { - return QString::fromLocal8Bit(err.asString()); + + if (ctx->protocol() == OpenPGP) { + if ((err = ctx->getAuditLog(data, OpenPGPAuditLogFlags))) { + return QString::fromLocal8Bit(err.asString()); + } + const QByteArray ba = dp.data(); + return markupDiagnostics(QString::fromUtf8(ba.data(), ba.size())); + } + + if (ctx->protocol() == CMS) { + if ((err = ctx->lastError()) || (err = ctx->getAuditLog(data, CMSAuditLogFlags))) { + return QString::fromLocal8Bit(err.asString()); + } + const QByteArray ba = dp.data(); + return QString::fromUtf8(ba.data(), ba.size()); } - const QByteArray ba = dp.data(); - return QString::fromUtf8(ba.data(), ba.size()); + + return QStringLiteral("Unsupported protocol for Audit Log"); } static QList from_sl(const QStringList &sl) commit 629afebe5017db97f2a318f6878fe1f9d3e60189 Author: Andre Heinecke Date: Thu Jul 5 10:22:13 2018 +0200 cpp: Add enum mapping for GPGME_AUDIT_LOG_DIAG * src/context.cpp (to_auditlog_flags): Map DIAG value. * src/context.h (AuditLogFlags): Add it. diff --git a/lang/cpp/src/context.cpp b/lang/cpp/src/context.cpp index aab22cd..1e4e549 100644 --- a/lang/cpp/src/context.cpp +++ b/lang/cpp/src/context.cpp @@ -1028,6 +1028,9 @@ unsigned int to_auditlog_flags(unsigned int flags) if (flags & Context::AuditLogWithHelp) { result |= GPGME_AUDITLOG_WITH_HELP; } + if (flags & Context::DiagnosticAuditLog) { + result |= GPGME_AUDITLOG_DIAG; + } return result; } diff --git a/lang/cpp/src/context.h b/lang/cpp/src/context.h index a14625e..6e27daa 100644 --- a/lang/cpp/src/context.h +++ b/lang/cpp/src/context.h @@ -401,7 +401,9 @@ public: // // enum AuditLogFlags { + DefaultAuditLog = 0, HtmlAuditLog = 1, + DiagnosticAuditLog = 2, AuditLogWithHelp = 128 }; GpgME::Error startGetAuditLog(Data &output, unsigned int flags = 0); commit a2458806f8bf04b66795e1dde765b42fe1ef6797 Author: Andre Heinecke Date: Wed Jul 4 15:39:01 2018 +0200 core: Add gpg auditlog to get diagnostics * src/engine-gpg.c (engine_gpg): Add diagnostics member. (gpg_release): Release diagnostics data. (gpg_new): Set up logger-fd and diagnostics. (gpg_getauditlog): New. Copy diagnostics to a user data. (engine_ops): Add getauditlog. * src/engine-gpgsm.c (gpgsm_getauditlog): Return not implemented for GPGME_AUDITLOG_DIAG. * src/getauditlog.c (getauditlog_start): Don't reset engine for diagnostics. * src/gpgme.h.in (GPGME_AUDITLOG_DIAG): New. (GPGME_AUDITLOG_DEFAULT): New alias to 0. * tests/run-decrypt.c (show_usage, main): Add --diagnostics. * doc/gpgme.texi(Additional Logs): Document getauditlog. -- This enables users of GPGME to get more verbose information from gpg which can assist users in figuring out a problem that was before hidden behind a generalized error like "Decryption Failed". For GPGSM it is not yet available as it is problematic to get it properly in server mode and GPGSM already had the original audit log mechanism in place. GPGME_AUDITLOG_DEFAULT was added for a more explicit documentation. diff --git a/NEWS b/NEWS index 6c33c25..9c64110 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,8 @@ Noteworthy changes in version 1.11.2 (unreleased) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ gpgme_decrypt_result_t EXTENDED: New field legacy_cipher_nomdc. gpgme_set_ctx_flag EXTENDED: New flag 'ignore-mdc-error'. + GPGME_AUDITLOG_DEFAULT NEW. + GPGME_AUDITLOG_DIAG NEW. cpp: DecryptionResult::sessionKey NEW. cpp: DecryptionResult::symkeyAlgo NEW. cpp: DecryptionResult::isLegacyCipherNoMDC New. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index e3445a0..3dac60d 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -2426,6 +2426,7 @@ started. In fact, these references are accessed through the * Progress Meter Callback:: Being informed about the progress. * Status Message Callback:: Status messages received from gpg. * Locale:: Setting the locale of a context. +* Additional Logs:: Additional logs of a context. @end menu @@ -3155,6 +3156,70 @@ The function returns an error if not enough memory is available. @end deftypefun + at node Additional Logs + at subsection Additional Logs + at cindex auditlog, of the engine + at cindex auditlog + +Additional logs can be associated with a context. These logs are +engine specific and can be be obtained with @code{gpgme_op_getauditlog}. + + at deftypefun gpgme_error_t gpgme_op_getauditlog @ + (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_data_t @var{output}}, @ + @w{unsigned int @var{flags}}) + at since{1.1.1} + +The function @code{gpgme_op_getauditlog} is used to obtain additional +logs as specified by @var{flags} into the @var{output} data. If + +The function returns the error code @code{GPG_ERR_NO_ERROR} if a +log could be queried from the engine, and @code{GPG_ERR_NOT_IMPLEMENTED} +if the log specified in @var{flags} is not available for this engine. +If no log is available @code{GPG_ERR_NO_DATA} is returned. + +The value in @var{flags} is a bitwise-or combination of one or +multiple of the following bit values: + + at table @code + at item GPGME_AUDITLOG_DIAG + at since{1.11.2} + +Obtain diagnostic output which would be written to @code{stderr} in +interactive use of the engine. This can be used to provide additional +diagnostic information in case of errors in other operations. + +Note: If log-file has been set in the configuration the log will +be empty and @code{GPG_ERR_NO_DATA} will be returned. + +Implemented for: @code{GPGME_PROTOCOL_OpenPGP} + + at item GPGME_AUDITLOG_DEFAULT + at since{1.11.2} + +This flag has the value 0 for compatibility reasons. Obtains additional +information from the engine by issuing the @code{GETAUDITLOG} command. +For @code{GPGME_PROTOCOL_CMS} this provides additional information about +the X509 certificate chain. + +Implemented for: @code{GPGME_PROTOCOL_CMS} + + at item GPGME_AUDITLOG_HTML + at since{1.1.1} + +Same as @code{GPGME_AUDITLOG_DEFAULT} but in HTML. + +Implemented for: @code{GPGME_PROTOCOL_CMS} + at end table + at end deftypefun + + at deftypefun gpgme_error_t gpgme_op_getauditlog_start @ + (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_data_t @var{output}}, @ + @w{unsigned int @var{flags}}) + at since{1.1.1} + +This is the asynchronous variant of @code{gpgme_op_getauditlog}. + at end deftypefun + @node Key Management @section Key Management @cindex key management diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 802af08..f096bcb 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -149,6 +149,9 @@ struct engine_gpg /* NULL or the data object fed to --override_session_key-fd. */ gpgme_data_t override_session_key; + + /* Memory data containing diagnostics (--logger-fd) of gpg */ + gpgme_data_t diagnostics; }; typedef struct engine_gpg *engine_gpg_t; @@ -452,6 +455,7 @@ gpg_release (void *engine) free (gpg->cmd.keyword); gpgme_data_release (gpg->override_session_key); + gpgme_data_release (gpg->diagnostics); free (gpg); } @@ -620,6 +624,16 @@ gpg_new (void **engine, const char *file_name, const char *home_dir, } } + rc = gpgme_data_new (&gpg->diagnostics); + if (rc) + goto leave; + + rc = add_arg (gpg, "--logger-fd"); + if (rc) + goto leave; + + rc = add_data (gpg, gpg->diagnostics, -2, 1); + leave: if (rc) gpg_release (gpg); @@ -3243,6 +3257,52 @@ gpg_set_pinentry_mode (void *engine, gpgme_pinentry_mode_t mode) } +static gpgme_error_t +gpg_getauditlog (void *engine, gpgme_data_t output, unsigned int flags) +{ + engine_gpg_t gpg = engine; +#define MYBUFLEN 4096 + char buf[MYBUFLEN]; + int nread; + int any_written = 0; + + if (!(flags & GPGME_AUDITLOG_DIAG)) + { + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + } + + if (!gpg || !output) + { + return gpg_error (GPG_ERR_INV_VALUE); + } + + if (!gpg->diagnostics) + { + return gpg_error (GPG_ERR_GENERAL); + } + + gpgme_data_rewind (gpg->diagnostics); + + while ((nread = gpgme_data_read (gpg->diagnostics, buf, MYBUFLEN)) > 0) + { + any_written = 1; + if (gpgme_data_write (output, buf, nread) == -1) + return gpg_error_from_syserror (); + } + if (!any_written) + { + return gpg_error (GPG_ERR_NO_DATA); + } + + if (nread == -1) + return gpg_error_from_syserror (); + + gpgme_data_rewind (output); + return 0; +#undef MYBUFLEN +} + + struct engine_ops _gpgme_engine_ops_gpg = { @@ -3280,7 +3340,7 @@ struct engine_ops _gpgme_engine_ops_gpg = gpg_sign, gpg_trustlist, gpg_verify, - NULL, /* getauditlog */ + gpg_getauditlog, NULL, /* opassuan_transact */ NULL, /* conf_load */ NULL, /* conf_save */ diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index 84a9315..3266e36 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -2064,6 +2064,9 @@ gpgsm_getauditlog (void *engine, gpgme_data_t output, unsigned int flags) if (!gpgsm || !output) return gpg_error (GPG_ERR_INV_VALUE); + if ((flags & GPGME_AUDITLOG_DIAG)) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + #if USE_DESCRIPTOR_PASSING gpgsm->output_cb.data = output; err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0); diff --git a/src/getauditlog.c b/src/getauditlog.c index dbaf260..d70e66f 100644 --- a/src/getauditlog.c +++ b/src/getauditlog.c @@ -47,9 +47,12 @@ getauditlog_start (gpgme_ctx_t ctx, int synchronous, if (!output) return gpg_error (GPG_ERR_INV_VALUE); - err = _gpgme_op_reset (ctx, ((synchronous&255) | 256) ); - if (err) - return err; + if (!(flags & GPGME_AUDITLOG_DIAG)) + { + err = _gpgme_op_reset (ctx, ((synchronous&255) | 256) ); + if (err) + return err; + } _gpgme_engine_set_status_handler (ctx->engine, getauditlog_status_handler, ctx); diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 5279f6a..421199a 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -404,7 +404,9 @@ typedef unsigned int gpgme_export_mode_t; /* Flags for the audit log functions. */ +#define GPGME_AUDITLOG_DEFAULT 0 #define GPGME_AUDITLOG_HTML 1 +#define GPGME_AUDITLOG_DIAG 2 #define GPGME_AUDITLOG_WITH_HELP 128 diff --git a/tests/run-decrypt.c b/tests/run-decrypt.c index 99a15c7..c9d9e72 100644 --- a/tests/run-decrypt.c +++ b/tests/run-decrypt.c @@ -88,6 +88,7 @@ show_usage (int ex) " --no-symkey-cache disable the use of that cache\n" " --ignore-mdc-error allow decryption of legacy data\n" " --unwrap remove only the encryption layer\n" + " --diagnostics print diagnostics\n" , stderr); exit (ex); } @@ -112,6 +113,7 @@ main (int argc, char **argv) int no_symkey_cache = 0; int ignore_mdc_error = 0; int raw_output = 0; + int diagnostics = 0; if (argc) { argc--; argv++; } @@ -177,6 +179,11 @@ main (int argc, char **argv) ignore_mdc_error = 1; argc--; argv++; } + else if (!strcmp (*argv, "--diagnostics")) + { + diagnostics = 1; + argc--; argv++; + } else if (!strcmp (*argv, "--unwrap")) { flags |= GPGME_DECRYPT_UNWRAP; @@ -283,6 +290,28 @@ main (int argc, char **argv) err = gpgme_op_decrypt_ext (ctx, flags, in, out); result = gpgme_op_decrypt_result (ctx); + + if (diagnostics) + { + gpgme_data_t diag; + gpgme_error_t diag_err; + + gpgme_data_new (&diag); + diag_err = gpgme_op_getauditlog (ctx, diag, GPGME_AUDITLOG_DIAG); + if (diag_err) + { + fprintf (stderr, PGM ": getting diagnostics failed: %s\n", + gpgme_strerror (diag_err)); + } + else + { + fputs ("Begin Diagnostics:\n", stdout); + print_data (diag); + fputs ("End Diagnostics.\n", stdout); + } + gpgme_data_release (diag); + } + if (err) { fprintf (stderr, PGM ": decrypt failed: %s\n", gpgme_strerror (err)); ----------------------------------------------------------------------- Summary of changes: NEWS | 2 ++ doc/gpgme.texi | 65 ++++++++++++++++++++++++++++++++++++++++ lang/cpp/src/context.cpp | 3 ++ lang/cpp/src/context.h | 2 ++ lang/qt/src/threadedjobmixin.cpp | 32 ++++++++++++++++---- src/engine-gpg.c | 62 +++++++++++++++++++++++++++++++++++++- src/engine-gpgsm.c | 3 ++ src/getauditlog.c | 9 ++++-- src/gpgme.h.in | 2 ++ tests/run-decrypt.c | 29 ++++++++++++++++++ 10 files changed, 200 insertions(+), 9 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 5 21:04:04 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 05 Jul 2018 21:04:04 +0200 Subject: [git] GnuPG - branch, master, updated. gnupg-2.2.7-172-gf7526c7 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via f7526c7bc754acf68bde0b79c785e875a9365d60 (commit) from 9ea9b9db7e1b3e6a84104a2be48d492f12c6316c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit f7526c7bc754acf68bde0b79c785e875a9365d60 Author: Werner Koch Date: Thu Jul 5 20:55:32 2018 +0200 gpg: Prepare for signatures with ISSUER_FPR but without ISSUER. * g10/getkey.c (get_pubkey_for_sig): New. (get_pubkeyblock_for_sig): New. * g10/mainproc.c (issuer_fpr_raw): Give global scope. (check_sig_and_print): Use get_pubkeyblock_for_sig. * g10/pkclist.c (check_signatures_trust): Use get_pubkey_for_sig. * g10/sig-check.c (check_signature2): Ditto. (check_signature_over_key_or_uid): Ditto. -- GnuPG-bug-id: 4046 The whole getkey stuff is still a mess with way to much duplication and missing caching of already fetched data. Signed-off-by: Werner Koch diff --git a/g10/getkey.c b/g10/getkey.c index f0132bb..08e17e9 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -677,6 +677,24 @@ pk_from_block (PKT_public_key *pk, kbnode_t keyblock, kbnode_t found_key) } +/* Specialized version of get_pubkey which retrieves the key based on + * information in SIG. In contrast to get_pubkey PK is required. */ +gpg_error_t +get_pubkey_for_sig (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig) +{ + const byte *fpr; + size_t fprlen; + + /* First try the new ISSUER_FPR info. */ + fpr = issuer_fpr_raw (sig, &fprlen); + if (fpr && !get_pubkey_byfprint (ctrl, pk, NULL, fpr, fprlen)) + return 0; + + /* Fallback to use the ISSUER_KEYID. */ + return get_pubkey (ctrl, pk, sig->keyid); +} + + /* Return the public key with the key id KEYID and store it at PK. * The resources in *PK should be released using * release_public_key_parts(). This function also stores a copy of @@ -739,8 +757,9 @@ get_pubkey (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid) /* Do a lookup. */ { struct getkey_ctx_s ctx; - KBNODE kb = NULL; - KBNODE found_key = NULL; + kbnode_t kb = NULL; + kbnode_t found_key = NULL; + memset (&ctx, 0, sizeof ctx); ctx.exact = 1; /* Use the key ID exactly as given. */ ctx.not_allocated = 1; @@ -863,6 +882,28 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid) } +/* Return the entire keyblock used to create SIG. This is a + * specialized version of get_pubkeyblock. + * + * FIXME: This is a hack because get_pubkey_for_sig was already called + * and it could have used a cache to hold the key. */ +kbnode_t +get_pubkeyblock_for_sig (ctrl_t ctrl, PKT_signature *sig) +{ + const byte *fpr; + size_t fprlen; + kbnode_t keyblock; + + /* First try the new ISSUER_FPR info. */ + fpr = issuer_fpr_raw (sig, &fprlen); + if (fpr && !get_pubkey_byfprint (ctrl, NULL, &keyblock, fpr, fprlen)) + return keyblock; + + /* Fallback to use the ISSUER_KEYID. */ + return get_pubkeyblock (ctrl, sig->keyid); +} + + /* Return the key block for the key with key id KEYID or NULL, if an * error occurs. Use release_kbnode() to release the key block. * @@ -1802,6 +1843,8 @@ get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock, memset (&ctx, 0, sizeof ctx); ctx.exact = 1; ctx.not_allocated = 1; + /* FIXME: We should get the handle from the cache like we do in + * get_pubkey. */ ctx.kr_handle = keydb_new (); if (!ctx.kr_handle) return gpg_error_from_syserror (); diff --git a/g10/keydb.h b/g10/keydb.h index bd156a6..ea0fa9d 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -283,6 +283,10 @@ void cache_public_key( PKT_public_key *pk ); /* Disable and drop the public key cache. */ void getkey_disable_caches(void); +/* Return the public key used for signature SIG and store it at PK. */ +gpg_error_t get_pubkey_for_sig (ctrl_t ctrl, + PKT_public_key *pk, PKT_signature *sig); + /* Return the public key with the key id KEYID and store it at PK. */ int get_pubkey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid); @@ -291,6 +295,10 @@ int get_pubkey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid); also only considers primary keys. */ int get_pubkey_fast (PKT_public_key *pk, u32 *keyid); +/* Return the entire keyblock used to create SIG. This is a + * specialized version of get_pubkeyblock. */ +kbnode_t get_pubkeyblock_for_sig (ctrl_t ctrl, PKT_signature *sig); + /* Return the key block for the key with KEYID. */ kbnode_t get_pubkeyblock (ctrl_t ctrl, u32 *keyid); diff --git a/g10/mainproc.c b/g10/mainproc.c index a9da08f..1d56f1f 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -1751,7 +1751,7 @@ akl_has_wkd_method (void) /* Return the ISSUER fingerprint buffer and its lenbgth at R_LEN. * Returns NULL if not available. The returned buffer is valid as * long as SIG is not modified. */ -static const byte * +const byte * issuer_fpr_raw (PKT_signature *sig, size_t *r_len) { const byte *p; @@ -1768,7 +1768,7 @@ issuer_fpr_raw (PKT_signature *sig, size_t *r_len) } -/* Return the ISSUER fingerprint string in human readbale format if +/* Return the ISSUER fingerprint string in human readable format if * available. Caller must release the string. */ /* FIXME: Move to another file. */ char * @@ -2134,7 +2134,7 @@ check_sig_and_print (CTX c, kbnode_t node) * keyblock has already been fetched. Thus we could use the * fingerprint or PK itself to lookup the entire keyblock. That * would best be done with a cache. */ - keyblock = get_pubkeyblock (c->ctrl, sig->keyid); + keyblock = get_pubkeyblock_for_sig (c->ctrl, sig); snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX [uncertain] ", (ulong)sig->keyid[0], (ulong)sig->keyid[1]); diff --git a/g10/packet.h b/g10/packet.h index 40a8c4b..6957686 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -621,6 +621,7 @@ int proc_signature_packets_by_fd (ctrl_t ctrl, int proc_encryption_packets (ctrl_t ctrl, void *ctx, iobuf_t a); int list_packets( iobuf_t a ); +const byte *issuer_fpr_raw (PKT_signature *sig, size_t *r_len); char *issuer_fpr_string (PKT_signature *sig); /*-- parse-packet.c --*/ diff --git a/g10/pkclist.c b/g10/pkclist.c index 2322f78..e748443 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -548,7 +548,7 @@ check_signatures_trust (ctrl_t ctrl, PKT_signature *sig) unsigned int trustlevel = TRUST_UNKNOWN; int rc=0; - rc = get_pubkey (ctrl, pk, sig->keyid ); + rc = get_pubkey_for_sig (ctrl, pk, sig); if (rc) { /* this should not happen */ log_error("Ooops; the key vanished - can't check the trust\n"); diff --git a/g10/sig-check.c b/g10/sig-check.c index a68e031..0ec3843 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -156,7 +156,7 @@ check_signature2 (ctrl_t ctrl, log_info(_("WARNING: signature digest conflict in message\n")); rc = gpg_error (GPG_ERR_GENERAL); } - else if (get_pubkey (ctrl, pk, sig->keyid)) + else if (get_pubkey_for_sig (ctrl, pk, sig)) rc = gpg_error (GPG_ERR_NO_PUBKEY); else if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION, pk->pubkey_algo, pk->pkey, @@ -926,7 +926,7 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer, if (IS_CERT (sig)) signer->req_usage = PUBKEY_USAGE_CERT; - rc = get_pubkey (ctrl, signer, sig->keyid); + rc = get_pubkey_for_sig (ctrl, signer, sig); if (rc) { xfree (signer); ----------------------------------------------------------------------- Summary of changes: g10/getkey.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- g10/keydb.h | 8 ++++++++ g10/mainproc.c | 6 +++--- g10/packet.h | 1 + g10/pkclist.c | 2 +- g10/sig-check.c | 4 ++-- 6 files changed, 60 insertions(+), 8 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 5 21:48:13 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 05 Jul 2018 21:48:13 +0200 Subject: [git] GnuPG - branch, master, updated. gnupg-2.2.7-173-gcb71573 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via cb71573f376235036c98143155e964a15cfcb250 (commit) from f7526c7bc754acf68bde0b79c785e875a9365d60 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit cb71573f376235036c98143155e964a15cfcb250 Author: Werner Koch Date: Thu Jul 5 21:39:53 2018 +0200 po: Add flag options for xgettext. * po/Makevars (XGETTEXT_OPTIONS): Add --flag options. -- GnuPG-bug-id: 4053, 4054 Signed-off-by: Werner Koch diff --git a/po/Makevars b/po/Makevars index 485c72c..90b0c5b 100644 --- a/po/Makevars +++ b/po/Makevars @@ -8,7 +8,63 @@ subdir = po top_builddir = .. # These options get passed to xgettext. -XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ --keyword=L_ +XGETTEXT_OPTIONS = \ + --keyword=_ --keyword=N_ --keyword=L_ \ + --flag=gcry_log_debug:1:c-format \ + --flag=gpgrt_fprintf:2:c-format \ + --flag=gpgrt_fprintf_unlocked:2:c-format \ + --flag=gpgrt_printf:1:c-format \ + --flag=gpgrt_printf_unlocked:1:c-format \ + --flag=gpgrt_vfprintf:2:c-format \ + --flag=gpgrt_vfprintf_unlocked:2:c-format \ + --flag=gpgrt_asprintf:2:c-format \ + --flag=gpgrt_vasprintf:2:c-format \ + --flag=gpgrt_bsprintf:1:c-format \ + --flag=gpgrt_vbsprintf:1:c-format \ + --flag=gpgrt_snprintf:3:c-format \ + --flag=gpgrt_vsnprintf:3:c-format \ + --flag=gpgrt_log:2:c-format \ + --flag=gpgrt_log_bug:1:c-format \ + --flag=gpgrt_log_fatal:1:c-format \ + --flag=gpgrt_log_error:1:c-format \ + --flag=gpgrt_log_info:1:c-format \ + --flag=gpgrt_log_debug:1:c-format \ + --flag=gpgrt_log_debug_string:2:c-format \ + --flag=gpgrt_log_printf:1:c-format \ + --flag=gpgrt_log_printhex:3:c-format \ + --flag=gpgrt_log_clock:1:c-format \ + --flag=log_log:2:c-format \ + --flag=log_bug:1:c-format \ + --flag=log_fatal:1:c-format \ + --flag=log_error:1:c-format \ + --flag=log_info:1:c-format \ + --flag=log_debug:1:c-format \ + --flag=log_debug_string:2:c-format \ + --flag=log_printf:1:c-format \ + --flag=log_printhex:3:c-format \ + --flag=log_clock:1:c-format + --flag=put_membuf_printf:2:c-format \ + --flag=tty_printf:1:c-format \ + --flag=tty_fprintf:2:c-format \ + --flag=tty_getf:1:c-format \ + --flag=writeout_para:2:c-format \ + --flag=writeout_li:3:c-format \ + --flag=writeout_rem:2:c-format \ + --flag=xasprintf:1:c-format \ + --flag=xtryasprintf:1:c-format \ + --flag=log_debug_with_string:2:c-format \ + --flag=print_assuan_status:3:c-format \ + --flag=vprint_assuan_status:3:c-format \ + --flag=agent_print_status:3:c-format \ + --flag=dirmngr_status_helpf:2:c-format \ + --flag=dirmngr_status_printf:3:c-format \ + --flag=ks_printf_help:2:c-format \ + --flag=print_further_info:1:c-format \ + --flag=write_status_printf:2:c-format \ + --flag=kbxd_print_status:3:c-format \ + --flag=gpgconf_write_status:2:c-format \ + --flag=wks_write_status:2:c-format + # This is the copyright holder that gets inserted into the header of the # $(DOMAIN).pot file. Set this to the copyright holder of the surrounding diff --git a/po/POTFILES.in b/po/POTFILES.in index f19cb49..fe8d45f 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -26,7 +26,6 @@ common/gettime.c common/ksba-io-support.c common/argparse.c -common/logging.c common/utf8conv.c common/dotlock.c common/init.c ----------------------------------------------------------------------- Summary of changes: po/Makevars | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- po/POTFILES.in | 1 - 2 files changed, 57 insertions(+), 2 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 5 21:54:15 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 05 Jul 2018 21:54:15 +0200 Subject: [git] GnuPG - branch, STABLE-BRANCH-2-2, updated. gnupg-2.2.8-23-g833738a Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, STABLE-BRANCH-2-2 has been updated via 833738a316977ee774399bd658d535216dff22e9 (commit) via 221af19351addcdc28a1cd533c8628cfa3841671 (commit) from 063cf45c142f33815bc0f31d0fb3e1b25ca57b8c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 833738a316977ee774399bd658d535216dff22e9 Author: Werner Koch Date: Thu Jul 5 21:43:25 2018 +0200 po: Add flag options for xgettext. * po/Makevars (XGETTEXT_OPTIONS): Add --flag options. -- GnuPG-bug-id: 4053, 4054 Signed-off-by: Werner Koch diff --git a/po/Makevars b/po/Makevars index 485c72c..b538f19 100644 --- a/po/Makevars +++ b/po/Makevars @@ -8,7 +8,61 @@ subdir = po top_builddir = .. # These options get passed to xgettext. -XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ --keyword=L_ +XGETTEXT_OPTIONS = \ + --keyword=_ --keyword=N_ --keyword=L_ \ + --flag=gcry_log_debug:1:c-format \ + --flag=gpgrt_fprintf:2:c-format \ + --flag=gpgrt_fprintf_unlocked:2:c-format \ + --flag=gpgrt_printf:1:c-format \ + --flag=gpgrt_printf_unlocked:1:c-format \ + --flag=gpgrt_vfprintf:2:c-format \ + --flag=gpgrt_vfprintf_unlocked:2:c-format \ + --flag=gpgrt_asprintf:2:c-format \ + --flag=gpgrt_vasprintf:2:c-format \ + --flag=gpgrt_bsprintf:1:c-format \ + --flag=gpgrt_vbsprintf:1:c-format \ + --flag=gpgrt_snprintf:3:c-format \ + --flag=gpgrt_vsnprintf:3:c-format \ + --flag=gpgrt_log:2:c-format \ + --flag=gpgrt_log_bug:1:c-format \ + --flag=gpgrt_log_fatal:1:c-format \ + --flag=gpgrt_log_error:1:c-format \ + --flag=gpgrt_log_info:1:c-format \ + --flag=gpgrt_log_debug:1:c-format \ + --flag=gpgrt_log_debug_string:2:c-format \ + --flag=gpgrt_log_printf:1:c-format \ + --flag=gpgrt_log_printhex:3:c-format \ + --flag=gpgrt_log_clock:1:c-format \ + --flag=log_log:2:c-format \ + --flag=log_bug:1:c-format \ + --flag=log_fatal:1:c-format \ + --flag=log_error:1:c-format \ + --flag=log_info:1:c-format \ + --flag=log_debug:1:c-format \ + --flag=log_debug_string:2:c-format \ + --flag=log_printf:1:c-format \ + --flag=log_printhex:3:c-format \ + --flag=log_clock:1:c-format + --flag=put_membuf_printf:2:c-format \ + --flag=tty_printf:1:c-format \ + --flag=tty_fprintf:2:c-format \ + --flag=tty_getf:1:c-format \ + --flag=writeout_para:2:c-format \ + --flag=writeout_li:3:c-format \ + --flag=writeout_rem:2:c-format \ + --flag=xasprintf:1:c-format \ + --flag=xtryasprintf:1:c-format \ + --flag=log_debug_with_string:2:c-format \ + --flag=print_assuan_status:3:c-format \ + --flag=vprint_assuan_status:3:c-format \ + --flag=agent_print_status:3:c-format \ + --flag=dirmngr_status_helpf:2:c-format \ + --flag=dirmngr_status_printf:3:c-format \ + --flag=ks_printf_help:2:c-format \ + --flag=print_further_info:1:c-format \ + --flag=write_status_printf:2:c-format \ + --flag=gpgconf_write_status:2:c-format \ + --flag=wks_write_status:2:c-format # This is the copyright holder that gets inserted into the header of the # $(DOMAIN).pot file. Set this to the copyright holder of the surrounding commit 221af19351addcdc28a1cd533c8628cfa3841671 Author: Werner Koch Date: Thu Jul 5 20:55:32 2018 +0200 gpg: Prepare for signatures with ISSUER_FPR but without ISSUER. * g10/getkey.c (get_pubkey_for_sig): New. (get_pubkeyblock_for_sig): New. * g10/mainproc.c (issuer_fpr_raw): Give global scope. (check_sig_and_print): Use get_pubkeyblock_for_sig. * g10/pkclist.c (check_signatures_trust): Use get_pubkey_for_sig. * g10/sig-check.c (check_signature2): Ditto. (check_signature_over_key_or_uid): Ditto. -- GnuPG-bug-id: 4046 The whole getkey stuff is still a mess with way to much duplication and missing caching of already fetched data. Signed-off-by: Werner Koch (cherry picked from commit f7526c7bc754acf68bde0b79c785e875a9365d60) diff --git a/g10/getkey.c b/g10/getkey.c index 7c407dd..d76e7cc 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -677,6 +677,24 @@ pk_from_block (PKT_public_key *pk, kbnode_t keyblock, kbnode_t found_key) } +/* Specialized version of get_pubkey which retrieves the key based on + * information in SIG. In contrast to get_pubkey PK is required. */ +gpg_error_t +get_pubkey_for_sig (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig) +{ + const byte *fpr; + size_t fprlen; + + /* First try the new ISSUER_FPR info. */ + fpr = issuer_fpr_raw (sig, &fprlen); + if (fpr && !get_pubkey_byfprint (ctrl, pk, NULL, fpr, fprlen)) + return 0; + + /* Fallback to use the ISSUER_KEYID. */ + return get_pubkey (ctrl, pk, sig->keyid); +} + + /* Return the public key with the key id KEYID and store it at PK. * The resources in *PK should be released using * release_public_key_parts(). This function also stores a copy of @@ -739,8 +757,9 @@ get_pubkey (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid) /* Do a lookup. */ { struct getkey_ctx_s ctx; - KBNODE kb = NULL; - KBNODE found_key = NULL; + kbnode_t kb = NULL; + kbnode_t found_key = NULL; + memset (&ctx, 0, sizeof ctx); ctx.exact = 1; /* Use the key ID exactly as given. */ ctx.not_allocated = 1; @@ -863,6 +882,28 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid) } +/* Return the entire keyblock used to create SIG. This is a + * specialized version of get_pubkeyblock. + * + * FIXME: This is a hack because get_pubkey_for_sig was already called + * and it could have used a cache to hold the key. */ +kbnode_t +get_pubkeyblock_for_sig (ctrl_t ctrl, PKT_signature *sig) +{ + const byte *fpr; + size_t fprlen; + kbnode_t keyblock; + + /* First try the new ISSUER_FPR info. */ + fpr = issuer_fpr_raw (sig, &fprlen); + if (fpr && !get_pubkey_byfprint (ctrl, NULL, &keyblock, fpr, fprlen)) + return keyblock; + + /* Fallback to use the ISSUER_KEYID. */ + return get_pubkeyblock (ctrl, sig->keyid); +} + + /* Return the key block for the key with key id KEYID or NULL, if an * error occurs. Use release_kbnode() to release the key block. * @@ -1802,6 +1843,8 @@ get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock, memset (&ctx, 0, sizeof ctx); ctx.exact = 1; ctx.not_allocated = 1; + /* FIXME: We should get the handle from the cache like we do in + * get_pubkey. */ ctx.kr_handle = keydb_new (); if (!ctx.kr_handle) return gpg_error_from_syserror (); diff --git a/g10/keydb.h b/g10/keydb.h index c5671d6..70949e4 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -282,6 +282,10 @@ void cache_public_key( PKT_public_key *pk ); /* Disable and drop the public key cache. */ void getkey_disable_caches(void); +/* Return the public key used for signature SIG and store it at PK. */ +gpg_error_t get_pubkey_for_sig (ctrl_t ctrl, + PKT_public_key *pk, PKT_signature *sig); + /* Return the public key with the key id KEYID and store it at PK. */ int get_pubkey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid); @@ -290,6 +294,10 @@ int get_pubkey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid); also only considers primary keys. */ int get_pubkey_fast (PKT_public_key *pk, u32 *keyid); +/* Return the entire keyblock used to create SIG. This is a + * specialized version of get_pubkeyblock. */ +kbnode_t get_pubkeyblock_for_sig (ctrl_t ctrl, PKT_signature *sig); + /* Return the key block for the key with KEYID. */ kbnode_t get_pubkeyblock (ctrl_t ctrl, u32 *keyid); diff --git a/g10/mainproc.c b/g10/mainproc.c index f5cc453..5fea867 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -1657,7 +1657,7 @@ akl_has_wkd_method (void) /* Return the ISSUER fingerprint buffer and its lenbgth at R_LEN. * Returns NULL if not available. The returned buffer is valid as * long as SIG is not modified. */ -static const byte * +const byte * issuer_fpr_raw (PKT_signature *sig, size_t *r_len) { const byte *p; @@ -1674,7 +1674,7 @@ issuer_fpr_raw (PKT_signature *sig, size_t *r_len) } -/* Return the ISSUER fingerprint string in human readbale format if +/* Return the ISSUER fingerprint string in human readable format if * available. Caller must release the string. */ /* FIXME: Move to another file. */ char * @@ -2042,7 +2042,7 @@ check_sig_and_print (CTX c, kbnode_t node) * keyblock has already been fetched. Thus we could use the * fingerprint or PK itself to lookup the entire keyblock. That * would best be done with a cache. */ - keyblock = get_pubkeyblock (c->ctrl, sig->keyid); + keyblock = get_pubkeyblock_for_sig (c->ctrl, sig); snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX [uncertain] ", (ulong)sig->keyid[0], (ulong)sig->keyid[1]); diff --git a/g10/packet.h b/g10/packet.h index dc4ce5f..e76e6af 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -605,6 +605,7 @@ int proc_signature_packets_by_fd (ctrl_t ctrl, int proc_encryption_packets (ctrl_t ctrl, void *ctx, iobuf_t a); int list_packets( iobuf_t a ); +const byte *issuer_fpr_raw (PKT_signature *sig, size_t *r_len); char *issuer_fpr_string (PKT_signature *sig); /*-- parse-packet.c --*/ diff --git a/g10/pkclist.c b/g10/pkclist.c index 03ad4c8..6f04249 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -548,7 +548,7 @@ check_signatures_trust (ctrl_t ctrl, PKT_signature *sig) unsigned int trustlevel = TRUST_UNKNOWN; int rc=0; - rc = get_pubkey (ctrl, pk, sig->keyid ); + rc = get_pubkey_for_sig (ctrl, pk, sig); if (rc) { /* this should not happen */ log_error("Ooops; the key vanished - can't check the trust\n"); diff --git a/g10/sig-check.c b/g10/sig-check.c index 6b9feeb..e59e0c9 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -156,7 +156,7 @@ check_signature2 (ctrl_t ctrl, log_info(_("WARNING: signature digest conflict in message\n")); rc = gpg_error (GPG_ERR_GENERAL); } - else if (get_pubkey (ctrl, pk, sig->keyid)) + else if (get_pubkey_for_sig (ctrl, pk, sig)) rc = gpg_error (GPG_ERR_NO_PUBKEY); else if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION, pk->pubkey_algo, pk->pkey, @@ -923,7 +923,7 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer, if (IS_CERT (sig)) signer->req_usage = PUBKEY_USAGE_CERT; - rc = get_pubkey (ctrl, signer, sig->keyid); + rc = get_pubkey_for_sig (ctrl, signer, sig); if (rc) { xfree (signer); ----------------------------------------------------------------------- Summary of changes: g10/getkey.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- g10/keydb.h | 8 ++++++++ g10/mainproc.c | 6 +++--- g10/packet.h | 1 + g10/pkclist.c | 2 +- g10/sig-check.c | 4 ++-- po/Makevars | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 7 files changed, 115 insertions(+), 9 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Fri Jul 6 08:37:34 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Fri, 06 Jul 2018 08:37:34 +0200 Subject: [git] GnuPG - branch, STABLE-BRANCH-2-2, updated. gnupg-2.2.8-24-gb4599a0 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, STABLE-BRANCH-2-2 has been updated via b4599a0449ead7dc5c0d922aa78b6168e625e15e (commit) from 833738a316977ee774399bd658d535216dff22e9 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit b4599a0449ead7dc5c0d922aa78b6168e625e15e Author: Werner Koch Date: Fri Jul 6 08:24:57 2018 +0200 gpg: Allow decryption using several passphrases in may cases. * g10/mainproc.c (symkey_decrypt_seskey): Check for a valid algorithm. (proc_symkey_enc): Clear passpharse on error from above function. -- This does not work reliable as stated in bug 3795 but we can try to fix ~95% of all cases. The real fix is to use AEAD which will come with 2.3 GnuPG-bug-id: 3795, 4050 Signed-off-by: Werner Koch diff --git a/g10/mainproc.c b/g10/mainproc.c index 5fea867..f4e3db6 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -271,6 +271,14 @@ symkey_decrypt_seskey (DEK *dek, byte *seskey, size_t slen) gcry_cipher_decrypt ( hd, seskey, slen, NULL, 0 ); gcry_cipher_close ( hd ); + /* 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. */ + if (openpgp_cipher_test_algo (seskey[0])) + return gpg_error (GPG_ERR_BAD_KEY); + /* Now we replace the dek components with the real session key to decrypt the contents of the sequencing packet. */ @@ -353,6 +361,13 @@ proc_symkey_enc (CTX c, PACKET *pkt) if (symkey_decrypt_seskey (c->dek, enc->seskey, enc->seskeylen)) { + 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; } ----------------------------------------------------------------------- Summary of changes: g10/mainproc.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Fri Jul 6 12:01:09 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Fri, 06 Jul 2018 12:01:09 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-36-g1fbcd7c Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via 1fbcd7cbfca750057fd8cb620257adb0a8f201ca (commit) via d89d06bfce3e4ebb0b86803431ffdd6ead9edd41 (commit) via 0c12a8d021cde4c7686887549eceb058fe3b26d4 (commit) from 61956b72ebf422d637c3aca934b4a027f791b862 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 1fbcd7cbfca750057fd8cb620257adb0a8f201ca Author: Andre Heinecke Date: Fri Jul 6 11:54:11 2018 +0200 Switch back to old check for reading pane for ol16 * src/ribbon-callbacks.cpp (get_mail_from_control): Use the same codepath as OL2010 and 13 for 2016 again, too. -- The crash in Outlook 2016 started to appear at some point. Now after various updates to Outlook I can no longer reproduce it. As the previewpane.wordeditor is not reliable. see: GnuPG-Bug-Id: T4056 We disable that codepath again. The crash report was GnuPG-Bug-Id: T3484 diff --git a/src/ribbon-callbacks.cpp b/src/ribbon-callbacks.cpp index c38dd55..e31d208 100644 --- a/src/ribbon-callbacks.cpp +++ b/src/ribbon-callbacks.cpp @@ -368,19 +368,28 @@ get_mail_from_control (LPDISPATCH ctrl, bool *none_selected) } else if (!strcmp (ctx_name.c_str(), "_Explorer")) { - if (g_ol_version_major >= 16) + /* Avoid showing wrong crypto state if we don't have a reading + pane. In that case the parser will finish for a mail which is gone + and the crypto state will not get updated. */ + if (0 /*g_ol_version_major >= 16 */) { - // Avoid showing wrong crypto state if we don't have a reading - // pane. In that case the parser will finish for a mail which is gone - // and the crypto state will not get updated. - // - // - // Somehow latest Outlook 2016 crashes when accessing the current view - // of the Explorer. This is even reproducible with - // GpgOL disabled and only with Outlook Spy active. If you select - // the explorer of an Outlook.com resource and then access - // the CurrentView and close the CurrentView again in Outlook Spy - // outlook crashes. + /* Some Versions of Outlook 2016 crashed when accessing the current view + of the Explorer. This was even reproducible with + GpgOL disabled and only with Outlook Spy active. If you selected + the explorer of an Outlook.com resource and then access + the CurrentView and close the CurrentView again in Outlook Spy + outlook crashes. See: T3484 + + The crash no longer occured at least since build 10228. As + I'm not sure which Version fixed the crash we don't do a version + check and just use the same codepath as for Outlook 2010 and + 2013 again. + + Accessing PreviewPane.WordEditor is not a good solution here as + it requires "Microsoft VBA for Office" (See T4056 ). + A possible solution for that might be to check if + "Mail.GetInspector().WordEditor()" returns NULL. In that case we + know that we also won't get a WordEditor in the preview pane. */ LPDISPATCH prevEdit = get_oom_object (context, "PreviewPane.WordEditor"); gpgol_release (prevEdit); if (!prevEdit) @@ -414,6 +423,7 @@ get_mail_from_control (LPDISPATCH ctrl, bool *none_selected) } } } + if (!*none_selected) { /* Accessing the selection item can trigger a load event commit d89d06bfce3e4ebb0b86803431ffdd6ead9edd41 Author: Andre Heinecke Date: Fri Jul 6 11:16:19 2018 +0200 Add log_addins oomhelp function * src/oomhelp.cpp, src/oomhelp.h (log_addins): New. (get_oom_object): Debug dispid. -- I could not find a place where the call to Item(x) does not result in the general 80020009 exception. Strange. There is something fishy here because "Item" has dispid 0. But this is also what OutlookSpy shows. diff --git a/src/oomhelp.cpp b/src/oomhelp.cpp index b0097d0..0826f49 100644 --- a/src/oomhelp.cpp +++ b/src/oomhelp.cpp @@ -316,10 +316,10 @@ get_oom_object (LPDISPATCH pStart, const char *fullname) SysFreeString (parmstr); if (hr != S_OK || vtResult.vt != VT_DISPATCH) { - log_debug ("%s:%s: failure: '%s' p=%p vt=%d hr=0x%x argErr=0x%x", + log_debug ("%s:%s: failure: '%s' p=%p vt=%d hr=0x%x argErr=0x%x dispid=0x%x", SRCNAME, __func__, name, vtResult.pdispVal, vtResult.vt, (unsigned int)hr, - (unsigned int)argErr); + (unsigned int)argErr, (unsigned int)dispid); dump_excepinfo (execpinfo); VariantClear (&vtResult); gpgol_release (pDisp); @@ -2119,3 +2119,60 @@ get_ol_ui_language () VariantClear (&var); return result; } + +void +log_addins () +{ + LPDISPATCH app = GpgolAddin::get_instance ()->get_application (); + + if (!app) + { + TRACEPOINT; + return; + } + + LPDISPATCH addins = get_oom_object (app, "COMAddins"); + + if (!addins) + { + TRACEPOINT; + return; + } + + std::string activeAddins; + int count = get_oom_int (addins, "Count"); + for (int i = 1; i <= count; i++) + { + std::string item = std::string ("Item(") + std::to_string (i) + ")"; + + LPDISPATCH addin = get_oom_object (addins, item.c_str ()); + + if (!addin) + { + TRACEPOINT; + continue; + } + bool connected = get_oom_bool (addin, "Connect"); + if (!connected) + { + gpgol_release (addin); + continue; + } + + char *progId = get_oom_string (addin, "ProgId"); + gpgol_release (addin); + + if (!progId) + { + TRACEPOINT; + continue; + } + activeAddins += std::string (progId) + "\n"; + xfree (progId); + } + gpgol_release (addins); + + log_debug ("%s:%s:Active Addins:\n%s", SRCNAME, __func__, + activeAddins.c_str ()); + return; +} diff --git a/src/oomhelp.h b/src/oomhelp.h index 8b8c7a4..d4fd0f5 100644 --- a/src/oomhelp.h +++ b/src/oomhelp.h @@ -339,6 +339,9 @@ LPDISPATCH create_mail (void); LPDISPATCH get_account_for_mail (const char *mbox); +/* Print all active addins to log */ +void log_addins (void); + /* Sender fallbacks. All return either null or a malloced address. */ char *get_sender_CurrentUser (LPDISPATCH mailitem); char *get_sender_Sender (LPDISPATCH mailitem); commit 0c12a8d021cde4c7686887549eceb058fe3b26d4 Author: Andre Heinecke Date: Fri Jul 6 11:15:12 2018 +0200 Add missing i18n for conf dialog * src/addin-options.cpp (i18n_noops): Add another option string. diff --git a/src/addin-options.cpp b/src/addin-options.cpp index 0286746..6d3da45 100644 --- a/src/addin-options.cpp +++ b/src/addin-options.cpp @@ -53,6 +53,7 @@ i18n_noops[] = { "attachments as PGP/Inline"), N_("S&elect crypto settings automatically " "for reply and forward"), + N_("&Prefer S/MIME when automatically resolving recipients"), /* Tooltips */ N_("Enable or disable any automated key handling."), ----------------------------------------------------------------------- Summary of changes: src/addin-options.cpp | 1 + src/oomhelp.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++++++-- src/oomhelp.h | 3 +++ src/ribbon-callbacks.cpp | 34 +++++++++++++++++---------- 4 files changed, 85 insertions(+), 14 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Sat Jul 7 19:42:46 2018 From: cvs at cvs.gnupg.org (by Ben McGinnes) Date: Sat, 07 Jul 2018 19:42:46 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-82-gcacca62 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via cacca62d06c6cf4a291f7ab2571cf52d671d140f (commit) from 66c2a99422dd9a52d8342165ed1d033c4f29b9e0 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit cacca62d06c6cf4a291f7ab2571cf52d671d140f Author: Ben McGinnes Date: Sun Jul 8 03:40:35 2018 +1000 python bindings: howto examples * Made sure all example scripts meet PEP8 compliance. * Required fixing approx. a dozen of them in minor ways. diff --git a/lang/python/examples/howto/decrypt-file.py b/lang/python/examples/howto/decrypt-file.py index b38acc7..2fe37f2 100755 --- a/lang/python/examples/howto/decrypt-file.py +++ b/lang/python/examples/howto/decrypt-file.py @@ -32,10 +32,10 @@ if len(sys.argv) == 3: newfile = sys.argv[2] elif len(sys.argv) == 2: ciphertext = sys.argv[1] - newfile = input("Enter path and filename of file to save decrypted data to: ") + newfile = input("Enter path and filename to save decrypted data to: ") else: ciphertext = input("Enter path and filename of encrypted file: ") - newfile = input("Enter path and filename of file to save decrypted data to: ") + newfile = input("Enter path and filename to save decrypted data to: ") with open(ciphertext, "rb") as cfile: try: diff --git a/lang/python/examples/howto/encrypt-file.py b/lang/python/examples/howto/encrypt-file.py index ad4e1ce..7c84a6f 100755 --- a/lang/python/examples/howto/encrypt-file.py +++ b/lang/python/examples/howto/encrypt-file.py @@ -3,6 +3,9 @@ from __future__ import absolute_import, division, unicode_literals +import gpg +import sys + # Copyright (C) 2018 Ben McGinnes # # This program is free software; you can redistribute it and/or modify it under @@ -24,9 +27,6 @@ from __future__ import absolute_import, division, unicode_literals # Lesser General Public along with this program; if not, see # . -import gpg -import sys - """ Encrypts a file to a specified key. If entering both the key and the filename on the command line, the key must be entered first. @@ -55,7 +55,7 @@ with open(filename, "rb") as f: with gpg.Context(armor=True) as ca: try: ciphertext, result, sign_result = ca.encrypt(text, recipients=rkey, - sign=False) + sign=False) with open("{0}.asc".format(filename), "wb") as fa: fa.write(ciphertext) except gpg.errors.InvalidRecipients as e: @@ -64,7 +64,7 @@ with gpg.Context(armor=True) as ca: with gpg.Context() as cg: try: ciphertext, result, sign_result = cg.encrypt(text, recipients=rkey, - sign=False) + sign=False) with open("{0}.gpg".format(filename), "wb") as fg: fg.write(ciphertext) except gpg.errors.InvalidRecipients as e: diff --git a/lang/python/examples/howto/encrypt-sign-file.py b/lang/python/examples/howto/encrypt-sign-file.py index 41aaac8..a08176b 100755 --- a/lang/python/examples/howto/encrypt-sign-file.py +++ b/lang/python/examples/howto/encrypt-sign-file.py @@ -3,6 +3,9 @@ from __future__ import absolute_import, division, unicode_literals +import gpg +import sys + # Copyright (C) 2018 Ben McGinnes # # This program is free software; you can redistribute it and/or modify it under @@ -24,9 +27,6 @@ from __future__ import absolute_import, division, unicode_literals # Lesser General Public along with this program; if not, see # . -import gpg -import sys - """ Signs and encrypts a file to a specified key. If entering both the key and the filename on the command line, the key must be entered first. @@ -58,13 +58,13 @@ with open(filename, "rb") as f: with gpg.Context(armor=True) as ca: ciphertext, result, sign_result = ca.encrypt(text, recipients=rkey, always_trust=True, - add_encrypt_to=True) + add_encrypt_to=True) with open("{0}.asc".format(filename), "wb") as fa: fa.write(ciphertext) with gpg.Context() as cg: ciphertext, result, sign_result = cg.encrypt(text, recipients=rkey, always_trust=True, - add_encrypt_to=True) + add_encrypt_to=True) with open("{0}.gpg".format(filename), "wb") as fg: fg.write(ciphertext) diff --git a/lang/python/examples/howto/encrypt-to-group-gullible.py b/lang/python/examples/howto/encrypt-to-group-gullible.py index 7ebfb6b..c96e829 100755 --- a/lang/python/examples/howto/encrypt-to-group-gullible.py +++ b/lang/python/examples/howto/encrypt-to-group-gullible.py @@ -3,6 +3,10 @@ from __future__ import absolute_import, division, unicode_literals +import gpg +import sys +from groups import group_lists + # Copyright (C) 2018 Ben McGinnes # # This program is free software; you can redistribute it and/or modify it under @@ -24,10 +28,6 @@ from __future__ import absolute_import, division, unicode_literals # Lesser General Public along with this program; if not, see # . -import gpg -import sys -from groups import group_lists - """ Uses the groups module to encrypt to multiple recipients. @@ -74,7 +74,7 @@ if klist is not None: add_encrypt_to=True, always_trust=True) with open("{0}.asc".format(filepath), "wb") as f: - f.write(ciphertext) + f.write(ciphertext) else: pass diff --git a/lang/python/examples/howto/encrypt-to-group-trustno1.py b/lang/python/examples/howto/encrypt-to-group-trustno1.py index 736c5f1..da0376b 100755 --- a/lang/python/examples/howto/encrypt-to-group-trustno1.py +++ b/lang/python/examples/howto/encrypt-to-group-trustno1.py @@ -3,6 +3,10 @@ from __future__ import absolute_import, division, unicode_literals +import gpg +import sys +from groups import group_lists + # Copyright (C) 2018 Ben McGinnes # # This program is free software; you can redistribute it and/or modify it under @@ -24,10 +28,6 @@ from __future__ import absolute_import, division, unicode_literals # Lesser General Public along with this program; if not, see # . -import gpg -import sys -from groups import group_lists - """ Uses the groups module to encrypt to multiple recipients. @@ -83,7 +83,7 @@ if klist is not None: except: pass with open("{0}.asc".format(filepath), "wb") as f: - f.write(ciphertext) + f.write(ciphertext) else: pass diff --git a/lang/python/examples/howto/encrypt-to-group.py b/lang/python/examples/howto/encrypt-to-group.py index 84f8d10..d4cb074 100755 --- a/lang/python/examples/howto/encrypt-to-group.py +++ b/lang/python/examples/howto/encrypt-to-group.py @@ -3,6 +3,10 @@ from __future__ import absolute_import, division, unicode_literals +import gpg +import sys +from groups import group_lists + # Copyright (C) 2018 Ben McGinnes # # This program is free software; you can redistribute it and/or modify it under @@ -24,10 +28,6 @@ from __future__ import absolute_import, division, unicode_literals # Lesser General Public along with this program; if not, see # . -import gpg -import sys -from groups import group_lists - """ Uses the groups module to encrypt to multiple recipients. @@ -84,7 +84,7 @@ if klist is not None: except: pass with open("{0}.asc".format(filepath), "wb") as f: - f.write(ciphertext) + f.write(ciphertext) else: pass diff --git a/lang/python/examples/howto/export-key.py b/lang/python/examples/howto/export-key.py index 41be64f..6def687 100755 --- a/lang/python/examples/howto/export-key.py +++ b/lang/python/examples/howto/export-key.py @@ -3,6 +3,10 @@ from __future__ import absolute_import, division, unicode_literals +import gpg +import os.path +import sys + # Copyright (C) 2018 Ben McGinnes # # This program is free software; you can redistribute it and/or modify it under @@ -24,10 +28,6 @@ from __future__ import absolute_import, division, unicode_literals # Lesser General Public along with this program; if not, see # . -import gpg -import os.path -import sys - print(""" This script exports one or more public keys. """) diff --git a/lang/python/examples/howto/export-minimised-key.py b/lang/python/examples/howto/export-minimised-key.py index d28b1cb..c2c533e 100755 --- a/lang/python/examples/howto/export-minimised-key.py +++ b/lang/python/examples/howto/export-minimised-key.py @@ -3,6 +3,10 @@ from __future__ import absolute_import, division, unicode_literals +import gpg +import os.path +import sys + # Copyright (C) 2018 Ben McGinnes # # This program is free software; you can redistribute it and/or modify it under @@ -24,10 +28,6 @@ from __future__ import absolute_import, division, unicode_literals # Lesser General Public along with this program; if not, see # . -import gpg -import os.path -import sys - print(""" This script exports one or more public keys in minimised form. """) diff --git a/lang/python/examples/howto/export-secret-key.py b/lang/python/examples/howto/export-secret-key.py index 8bbe409..e9c53fe 100755 --- a/lang/python/examples/howto/export-secret-key.py +++ b/lang/python/examples/howto/export-secret-key.py @@ -3,6 +3,11 @@ from __future__ import absolute_import, division, unicode_literals +import gpg +import os +import os.path +import sys + # Copyright (C) 2018 Ben McGinnes # # This program is free software; you can redistribute it and/or modify it under @@ -24,11 +29,6 @@ from __future__ import absolute_import, division, unicode_literals # Lesser General Public along with this program; if not, see # . -import gpg -import os -import os.path -import sys - print(""" This script exports one or more secret keys. diff --git a/lang/python/examples/howto/export-secret-keys.py b/lang/python/examples/howto/export-secret-keys.py index 03037c9..f0a791e 100755 --- a/lang/python/examples/howto/export-secret-keys.py +++ b/lang/python/examples/howto/export-secret-keys.py @@ -3,6 +3,12 @@ from __future__ import absolute_import, division, unicode_literals +import gpg +import os +import os.path +import subprocess +import sys + # Copyright (C) 2018 Ben McGinnes # # This program is free software; you can redistribute it and/or modify it under @@ -24,12 +30,6 @@ from __future__ import absolute_import, division, unicode_literals # Lesser General Public along with this program; if not, see # . -import gpg -import os -import os.path -import subprocess -import sys - print(""" This script exports one or more secret keys as both ASCII armored and binary file formats, saved in files within the user's GPG home directory. diff --git a/lang/python/examples/howto/import-key.py b/lang/python/examples/howto/import-key.py index 56cfe25..464052d 100755 --- a/lang/python/examples/howto/import-key.py +++ b/lang/python/examples/howto/import-key.py @@ -3,6 +3,10 @@ from __future__ import absolute_import, division, unicode_literals +import gpg +import os.path +import sys + # Copyright (C) 2018 Ben McGinnes # # This program is free software; you can redistribute it and/or modify it under @@ -24,10 +28,6 @@ from __future__ import absolute_import, division, unicode_literals # Lesser General Public along with this program; if not, see # . -import gpg -import os.path -import sys - print(""" This script exports one or more public keys. """) diff --git a/lang/python/examples/howto/import-keys.py b/lang/python/examples/howto/import-keys.py index 8a3bb29..bdc15a6 100755 --- a/lang/python/examples/howto/import-keys.py +++ b/lang/python/examples/howto/import-keys.py @@ -3,6 +3,10 @@ from __future__ import absolute_import, division, unicode_literals +import gpg +import os.path +import requests + # Copyright (C) 2018 Ben McGinnes # # This program is free software; you can redistribute it and/or modify it under @@ -24,21 +28,14 @@ from __future__ import absolute_import, division, unicode_literals # Lesser General Public along with this program; if not, see # . -import gpg -import os.path -import requests - print(""" This script imports one or more public keys from the SKS keyservers. """) -import gpg -import requests - c = gpg.Context() url = "https://sks-keyservers.net/pks/lookup" pattern = input("Enter the pattern to search for key or user IDs: ") -payload = { "op": "get", "search": pattern } +payload = {"op": "get", "search": pattern} r = requests.get(url, verify=True, params=payload) result = c.key_import(r.content) diff --git a/lang/python/examples/howto/temp-homedir-config.py b/lang/python/examples/howto/temp-homedir-config.py index ddd7932..3bb5cf3 100755 --- a/lang/python/examples/howto/temp-homedir-config.py +++ b/lang/python/examples/howto/temp-homedir-config.py @@ -3,6 +3,10 @@ from __future__ import absolute_import, division, unicode_literals +import os +import os.path +import sys + # Copyright (C) 2018 Ben McGinnes # # This program is free software; you can redistribute it and/or modify it under @@ -24,10 +28,6 @@ from __future__ import absolute_import, division, unicode_literals # Lesser General Public along with this program; if not, see # . -import os -import os.path -import sys - intro = """ This script creates a temporary directory to use as a homedir for testing key generation tasks with the correct permissions, along @@ -54,6 +54,13 @@ message telling you to specify a new directory name. There is no default directory name. """ +ciphers256 = "TWOFISH CAMELLIA256 AES256" +ciphers192 = "CAMELLIA192 AES192" +ciphers128 = "CAMELLIA128 AES" +ciphersBad = "BLOWFISH IDEA CAST5 3DES" +digests = "SHA512 SHA384 SHA256 SHA224 RIPEMD160 SHA1" +compress = "ZLIB BZIP2 ZIP Uncompressed" + gpgconf = """# gpg.conf settings for key generation: expert allow-freeform-uid @@ -63,11 +70,11 @@ tofu-default-policy unknown enable-large-rsa enable-dsa2 cert-digest-algo SHA512 -default-preference-list TWOFISH CAMELLIA256 AES256 CAMELLIA192 AES192 CAMELLIA128 AES BLOWFISH IDEA CAST5 3DES SHA512 SHA384 SHA256 SHA224 RIPEMD160 SHA1 ZLIB BZIP2 ZIP Uncompressed -personal-cipher-preferences TWOFISH CAMELLIA256 AES256 CAMELLIA192 AES192 CAMELLIA128 AES BLOWFISH IDEA CAST5 3DES -personal-digest-preferences SHA512 SHA384 SHA256 SHA224 RIPEMD160 SHA1 -personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed -""" +default-preference-list {0} {1} {2} {3} {4} {5} +personal-cipher-preferences {0} {1} {2} {3} +personal-digest-preferences {4} +personal-compress-preferences {5} +""".format(ciphers256, ciphers192, ciphers128, ciphersBad, digests, compress) agentconf = """# gpg-agent.conf settings for key generation: default-cache-ttl 300 ----------------------------------------------------------------------- Summary of changes: lang/python/examples/howto/decrypt-file.py | 4 ++-- lang/python/examples/howto/encrypt-file.py | 10 ++++----- lang/python/examples/howto/encrypt-sign-file.py | 10 ++++----- .../examples/howto/encrypt-to-group-gullible.py | 10 ++++----- .../examples/howto/encrypt-to-group-trustno1.py | 10 ++++----- lang/python/examples/howto/encrypt-to-group.py | 10 ++++----- lang/python/examples/howto/export-key.py | 8 +++---- lang/python/examples/howto/export-minimised-key.py | 8 +++---- lang/python/examples/howto/export-secret-key.py | 10 ++++----- lang/python/examples/howto/export-secret-keys.py | 12 +++++------ lang/python/examples/howto/import-key.py | 8 +++---- lang/python/examples/howto/import-keys.py | 13 +++++------ lang/python/examples/howto/temp-homedir-config.py | 25 ++++++++++++++-------- 13 files changed, 71 insertions(+), 67 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 9 09:58:51 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Mon, 09 Jul 2018 09:58:51 +0200 Subject: [git] GnuPG - branch, master, updated. gnupg-2.2.7-176-gc2fd65e Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via c2fd65ec8498a08ee36ca52d99b6b014f6db8d93 (commit) via 6c3567196f7e72552f326ce07dccbcce31926e5d (commit) via 135e46ea480d749b8a9692f71d4d0bfdadd8ee2f (commit) from cb71573f376235036c98143155e964a15cfcb250 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit c2fd65ec8498a08ee36ca52d99b6b014f6db8d93 Author: Werner Koch Date: Mon Jul 9 09:49:09 2018 +0200 gpg: Let export-clean remove expired subkeys. * g10/key-clean.h (KEY_CLEAN_NONE, KEY_CLEAN_INVALID) (KEY_CLEAN_ENCR, KEY_CLEAN_AUTHENCR, KEY_CLEAN_ALL): New. * g10/key-clean.c (clean_one_subkey): New. (clean_all_subkeys): Add arg CLEAN_LEVEL. * g10/import.c (import_one): Call clean_all_subkeys with KEY_CLEAN_NONE. * g10/export.c (do_export_stream): Call clean_all_subkeys depedning on the export clean options. -- GnuPG-bug-id: 3622 Signed-off-by: Werner Koch diff --git a/g10/export.c b/g10/export.c index 21ff23c..e94e959 100644 --- a/g10/export.c +++ b/g10/export.c @@ -2003,15 +2003,18 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, } /* Always do the cleaning on the public key part if requested. - * Note that both export-clean and export-minimal only apply to - * UID sigs (0x10, 0x11, 0x12, and 0x13). A designated - * revocation is never stripped, even with export-minimal set. */ + * A designated revocation is never stripped, even with + * export-minimal set. */ if ((options & EXPORT_CLEAN)) { merge_keys_and_selfsig (ctrl, keyblock); clean_all_uids (ctrl, keyblock, opt.verbose, (options&EXPORT_MINIMAL), NULL, NULL); - clean_all_subkeys (ctrl, keyblock, opt.verbose, NULL, NULL); + clean_all_subkeys (ctrl, keyblock, opt.verbose, + (options&EXPORT_MINIMAL)? KEY_CLEAN_ALL + /**/ : KEY_CLEAN_AUTHENCR, + NULL, NULL); + commit_kbnode (&keyblock); } if (export_keep_uid) diff --git a/g10/import.c b/g10/import.c index 66ff925..1eb3ecc 100644 --- a/g10/import.c +++ b/g10/import.c @@ -1764,7 +1764,8 @@ import_one (ctrl_t ctrl, merge_keys_and_selfsig (ctrl, keyblock); clean_all_uids (ctrl, keyblock, opt.verbose, (options&IMPORT_MINIMAL), NULL, NULL); - clean_all_subkeys (ctrl, keyblock, opt.verbose, NULL, NULL); + clean_all_subkeys (ctrl, keyblock, opt.verbose, KEY_CLEAN_NONE, + NULL, NULL); } clear_kbnode_flags( keyblock ); @@ -1910,7 +1911,8 @@ import_one (ctrl_t ctrl, merge_keys_and_selfsig (ctrl, keyblock); clean_all_uids (ctrl, keyblock, opt.verbose, (options&IMPORT_MINIMAL), &n_uids_cleaned,&n_sigs_cleaned); - clean_all_subkeys (ctrl, keyblock, opt.verbose, NULL, NULL); + clean_all_subkeys (ctrl, keyblock, opt.verbose, KEY_CLEAN_NONE, + NULL, NULL); } /* Unless we are in restore mode apply meta data to the @@ -2001,7 +2003,8 @@ import_one (ctrl_t ctrl, clean_all_uids (ctrl, keyblock_orig, opt.verbose, (options&IMPORT_MINIMAL), &n_uids_cleaned,&n_sigs_cleaned); - clean_all_subkeys (ctrl, keyblock_orig, opt.verbose, NULL, NULL); + clean_all_subkeys (ctrl, keyblock_orig, opt.verbose, KEY_CLEAN_NONE, + NULL, NULL); } if (n_uids || n_sigs || n_subk || n_sigs_cleaned || n_uids_cleaned) diff --git a/g10/key-clean.c b/g10/key-clean.c index 10478a4..097ca17 100644 --- a/g10/key-clean.c +++ b/g10/key-clean.c @@ -408,24 +408,101 @@ clean_all_uids (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, } +/* Helper for clean_all_subkeys. */ +static int +clean_one_subkey (ctrl_t ctrl, kbnode_t subkeynode, int noisy, int clean_level) +{ + kbnode_t node; + PKT_public_key *pk = subkeynode->pkt->pkt.public_key; + unsigned int use = pk->pubkey_usage; + int do_clean = 0; + + (void)ctrl; + (void)noisy; + + log_assert (subkeynode->pkt->pkttype == PKT_PUBLIC_SUBKEY + || subkeynode->pkt->pkttype == PKT_SECRET_SUBKEY); + + if (DBG_LOOKUP) + log_debug ("\tchecking subkey %08lX [%c%c%c%c%c]\n", + (ulong) keyid_from_pk (pk, NULL), + (use & PUBKEY_USAGE_ENC)? 'e':'-', + (use & PUBKEY_USAGE_SIG)? 's':'-', + (use & PUBKEY_USAGE_CERT)? 'c':'-', + (use & PUBKEY_USAGE_AUTH)? 'a':'-', + (use & PUBKEY_USAGE_UNKNOWN)? '?':'-'); + + if (!pk->flags.valid) + { + if (DBG_LOOKUP) + log_debug ("\tsubkey not valid\n"); + if (clean_level == KEY_CLEAN_INVALID) + do_clean = 1; + } + if (pk->has_expired) + { + if (DBG_LOOKUP) + log_debug ("\tsubkey has expired\n"); + if (clean_level == KEY_CLEAN_ALL) + do_clean = 1; + else if (clean_level == KEY_CLEAN_AUTHENCR + && (use & (PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH)) + && !(use & (PUBKEY_USAGE_SIG | PUBKEY_USAGE_CERT))) + do_clean = 1; + else if (clean_level == KEY_CLEAN_ENCR + && (use & PUBKEY_USAGE_ENC) + && !(use & (PUBKEY_USAGE_SIG | PUBKEY_USAGE_CERT + | PUBKEY_USAGE_AUTH))) + do_clean = 1; + } + if (pk->flags.revoked) + { + if (DBG_LOOKUP) + log_debug ("\tsubkey has been revoked (keeping)\n"); + /* Avoid any cleaning because revocations are important. */ + do_clean = 0; + } + if (!do_clean) + return 0; + + if (DBG_LOOKUP) + log_debug ("\t=> removing this subkey\n"); + + delete_kbnode (subkeynode); + for (node = subkeynode->next; + node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY + || node->pkt->pkttype == PKT_SECRET_SUBKEY); + node = node->next) + delete_kbnode (node); + + return 1; +} + + /* This function only marks the deleted nodes and the caller is * responsible to skip or remove them. Needs to be called after a - * merge_keys_and_selfsig. */ + * merge_keys_and_selfsig. CLEAN_LEVEL is one of the KEY_CLEAN_* + * values. */ void -clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, +clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, int clean_level, int *subkeys_cleaned, int *sigs_cleaned) { - kbnode_t node; + kbnode_t first_subkey, node; + + if (DBG_LOOKUP) + log_debug ("clean_all_subkeys: checking key %08lX\n", + (ulong) keyid_from_pk (keyblock->pkt->pkt.public_key, NULL)); for (node = keyblock->next; node; node = node->next) if (!is_deleted_kbnode (node) && (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY)) break; + first_subkey = node; /* Remove bogus subkey binding signatures: The only signatures * allowed are of class 0x18 and 0x28. */ - for (; node; node = node->next) + for (node = first_subkey; node; node = node->next) { if (is_deleted_kbnode (node)) continue; @@ -438,4 +515,21 @@ clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, ++*sigs_cleaned; } } + + /* Do the selected cleaning. */ + if (clean_level > KEY_CLEAN_NONE) + { + for (node = first_subkey; node; node = node->next) + { + if (is_deleted_kbnode (node)) + continue; + if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY + || node->pkt->pkttype == PKT_SECRET_SUBKEY) + if (clean_one_subkey (ctrl, node, noisy, clean_level)) + { + if (subkeys_cleaned) + ++*subkeys_cleaned; + } + } + } } diff --git a/g10/key-clean.h b/g10/key-clean.h index 6938430..a0fb769 100644 --- a/g10/key-clean.h +++ b/g10/key-clean.h @@ -23,6 +23,18 @@ #include "gpg.h" +/* No explict cleaning. */ +#define KEY_CLEAN_NONE 0 +/* Remove only invalid subkeys (ie. missing key-bindings) */ +#define KEY_CLEAN_INVALID 1 +/* Remove expired encryption keys */ +#define KEY_CLEAN_ENCR 2 +/* Remove expired authentication and encryption keys. */ +#define KEY_CLEAN_AUTHENCR 3 +/* Remove all expired subkeys. */ +#define KEY_CLEAN_ALL 4 + + void mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, u32 *main_kid, struct key_item *klist, u32 curtime, u32 *next_expire); @@ -32,7 +44,8 @@ void clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, int *uids_cleaned, int *sigs_cleaned); void clean_all_uids (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, int *uids_cleaned,int *sigs_cleaned); -void clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, +void clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, + int noisy, int clean_level, int *subkeys_cleaned, int *sigs_cleaned); commit 6c3567196f7e72552f326ce07dccbcce31926e5d Author: Werner Koch Date: Fri Jul 6 11:48:38 2018 +0200 gpg: Split key cleaning function for clarity. * g10/key-clean.c (clean_key): Rename to clean_all_uids and split subkey cleaning into ... (clean_all_subkeys): new. Call that always after the former clean_key invocations. -- Note that the clean_all_subkeys function will later be extended. Signed-off-by: Werner Koch diff --git a/g10/export.c b/g10/export.c index 44cf075..21ff23c 100644 --- a/g10/export.c +++ b/g10/export.c @@ -2007,8 +2007,12 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, * UID sigs (0x10, 0x11, 0x12, and 0x13). A designated * revocation is never stripped, even with export-minimal set. */ if ((options & EXPORT_CLEAN)) - clean_key (ctrl, keyblock, opt.verbose, - (options&EXPORT_MINIMAL), NULL, NULL); + { + merge_keys_and_selfsig (ctrl, keyblock); + clean_all_uids (ctrl, keyblock, opt.verbose, + (options&EXPORT_MINIMAL), NULL, NULL); + clean_all_subkeys (ctrl, keyblock, opt.verbose, NULL, NULL); + } if (export_keep_uid) { diff --git a/g10/import.c b/g10/import.c index 757063e..66ff925 100644 --- a/g10/import.c +++ b/g10/import.c @@ -1759,9 +1759,13 @@ import_one (ctrl_t ctrl, that we have to clean later. This has no practical impact on the end result, but does result in less logging which might confuse the user. */ - if (options&IMPORT_CLEAN) - clean_key (ctrl, keyblock, - opt.verbose, (options&IMPORT_MINIMAL), NULL, NULL); + if ((options & IMPORT_CLEAN)) + { + merge_keys_and_selfsig (ctrl, keyblock); + clean_all_uids (ctrl, keyblock, + opt.verbose, (options&IMPORT_MINIMAL), NULL, NULL); + clean_all_subkeys (ctrl, keyblock, opt.verbose, NULL, NULL); + } clear_kbnode_flags( keyblock ); @@ -1902,8 +1906,12 @@ import_one (ctrl_t ctrl, log_info (_("writing to '%s'\n"), keydb_get_resource_name (hd) ); if ((options & IMPORT_CLEAN)) - clean_key (ctrl, keyblock, opt.verbose, (options&IMPORT_MINIMAL), - &n_uids_cleaned,&n_sigs_cleaned); + { + merge_keys_and_selfsig (ctrl, keyblock); + clean_all_uids (ctrl, keyblock, opt.verbose, (options&IMPORT_MINIMAL), + &n_uids_cleaned,&n_sigs_cleaned); + clean_all_subkeys (ctrl, keyblock, opt.verbose, NULL, NULL); + } /* Unless we are in restore mode apply meta data to the * keyblock. Note that this will never change the first packet @@ -1988,8 +1996,13 @@ import_one (ctrl_t ctrl, goto leave; if ((options & IMPORT_CLEAN)) - clean_key (ctrl, keyblock_orig, opt.verbose, (options&IMPORT_MINIMAL), - &n_uids_cleaned,&n_sigs_cleaned); + { + merge_keys_and_selfsig (ctrl, keyblock_orig); + clean_all_uids (ctrl, keyblock_orig, opt.verbose, + (options&IMPORT_MINIMAL), + &n_uids_cleaned,&n_sigs_cleaned); + clean_all_subkeys (ctrl, keyblock_orig, opt.verbose, NULL, NULL); + } if (n_uids || n_sigs || n_subk || n_sigs_cleaned || n_uids_cleaned) { diff --git a/g10/key-clean.c b/g10/key-clean.c index d022ff4..10478a4 100644 --- a/g10/key-clean.c +++ b/g10/key-clean.c @@ -383,15 +383,14 @@ clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, /* NB: This function marks the deleted nodes only and the caller is - * responsible to skip or remove them. */ + * responsible to skip or remove them. Needs to be called after a + * merge_keys_and_selfsig(). */ void -clean_key (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, - int *uids_cleaned, int *sigs_cleaned) +clean_all_uids (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, + int *uids_cleaned, int *sigs_cleaned) { kbnode_t node; - merge_keys_and_selfsig (ctrl, keyblock); - for (node = keyblock->next; node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY); @@ -406,6 +405,26 @@ clean_key (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, * allowed are of class 0x18 and 0x28. */ log_assert (!node || (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY)); +} + + +/* This function only marks the deleted nodes and the caller is + * responsible to skip or remove them. Needs to be called after a + * merge_keys_and_selfsig. */ +void +clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, + int *subkeys_cleaned, int *sigs_cleaned) +{ + kbnode_t node; + + for (node = keyblock->next; node; node = node->next) + if (!is_deleted_kbnode (node) + && (node->pkt->pkttype == PKT_PUBLIC_SUBKEY + || node->pkt->pkttype == PKT_SECRET_SUBKEY)) + break; + + /* Remove bogus subkey binding signatures: The only signatures + * allowed are of class 0x18 and 0x28. */ for (; node; node = node->next) { if (is_deleted_kbnode (node)) diff --git a/g10/key-clean.h b/g10/key-clean.h index 4dfd950..6938430 100644 --- a/g10/key-clean.h +++ b/g10/key-clean.h @@ -30,8 +30,10 @@ void mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, void clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, int noisy, int self_only, int *uids_cleaned, int *sigs_cleaned); -void clean_key (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, - int *uids_cleaned,int *sigs_cleaned); +void clean_all_uids (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, + int *uids_cleaned,int *sigs_cleaned); +void clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, + int *subkeys_cleaned, int *sigs_cleaned); #endif /*GNUPG_G10_KEY_CLEAN_H*/ commit 135e46ea480d749b8a9692f71d4d0bfdadd8ee2f Author: Werner Koch Date: Fri Jul 6 11:40:16 2018 +0200 gpg: Move key cleaning functions to a separate file. * g10/trust.c (mark_usable_uid_certs, clean_sigs_from_uid) (clean_uid_from_key, clean_one_uid, clean_key): Move to ... * g10/key-clean.c: new file. * g10/key-clean.h: New. * g10/Makefile.am (gpg_sources): Add new files. * g10/export.c, g10/import.c, g10/keyedit.c, g10/trustdb.c: Include new header. * g10/trustdb.h (struct key_item, is_in_klist): Move to ... * g10/keydb.h: here. -- Signed-off-by: Werner Koch diff --git a/g10/Makefile.am b/g10/Makefile.am index b8b92d7..3b44643 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -152,6 +152,7 @@ gpg_sources = server.c \ trust.c $(trust_source) $(tofu_source) \ $(card_source) \ exec.c exec.h \ + key-clean.c key-clean.h \ key-check.c key-check.h gpg_SOURCES = gpg.c \ diff --git a/g10/export.c b/g10/export.c index c538dc1..44cf075 100644 --- a/g10/export.c +++ b/g10/export.c @@ -41,6 +41,8 @@ #include "../common/init.h" #include "trustdb.h" #include "call-agent.h" +#include "key-clean.h" + /* An object to keep track of subkeys. */ struct subkey_list_s diff --git a/g10/import.c b/g10/import.c index 5be7952..757063e 100644 --- a/g10/import.c +++ b/g10/import.c @@ -41,6 +41,7 @@ #include "../common/init.h" #include "../common/mbox-util.h" #include "key-check.h" +#include "key-clean.h" struct import_stats_s diff --git a/g10/trust.c b/g10/key-clean.c similarity index 58% copy from g10/trust.c copy to g10/key-clean.c index 6d4f0e7..d022ff4 100644 --- a/g10/trust.c +++ b/g10/key-clean.c @@ -1,7 +1,6 @@ -/* trust.c - High level trust functions - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, - * 2008, 2012 Free Software Foundation, Inc. - * Copyright (C) 2014 Werner Koch +/* key-clean.c - Functions to clean a keyblock + * Copyright (C) 1998-2008, 2010-2011 Free Software Foundation, Inc. + * Copyright (C) 2014, 2016-2018 Werner Koch * * This file is part of GnuPG. * @@ -17,6 +16,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see . + * SPDX-License-Identifier: GPL-3.0-or-later */ #include @@ -27,419 +27,14 @@ #include "gpg.h" #include "keydb.h" #include "../common/util.h" +#include "../common/host2net.h" +#include "../common/i18n.h" #include "options.h" #include "packet.h" #include "main.h" -#include "../common/i18n.h" -#include "trustdb.h" -#include "../common/host2net.h" - - -/* Return true if key is disabled. Note that this is usually used via - the pk_is_disabled macro. */ -int -cache_disabled_value (ctrl_t ctrl, PKT_public_key *pk) -{ -#ifdef NO_TRUST_MODELS - (void)pk; - return 0; -#else - return tdb_cache_disabled_value (ctrl, pk); -#endif -} - - -void -register_trusted_keyid (u32 *keyid) -{ -#ifdef NO_TRUST_MODELS - (void)keyid; -#else - tdb_register_trusted_keyid (keyid); -#endif -} - - -void -register_trusted_key (const char *string) -{ -#ifdef NO_TRUST_MODELS - (void)string; -#else - - /* Some users have conf files with entries like - * trusted-key 0x1234567812345678 # foo - * That is obviously wrong. Before fixing bug#1206 trailing garbage - * on a key specification if was ignored. We detect the above use case - * here and cut off the junk-looking-like-a comment. */ - if (strchr (string, '#')) - { - char *buf; - - buf = xtrystrdup (string); - if (buf) - { - *strchr (buf, '#') = 0; - tdb_register_trusted_key (buf); - xfree (buf); - return; - } - } - - tdb_register_trusted_key (string); -#endif -} - - - -/* - * This function returns a letter for a trust value. Trust flags - * are ignored. - */ -static int -trust_letter (unsigned int value) -{ - switch( (value & TRUST_MASK) ) - { - case TRUST_UNKNOWN: return '-'; - case TRUST_EXPIRED: return 'e'; - case TRUST_UNDEFINED: return 'q'; - case TRUST_NEVER: return 'n'; - case TRUST_MARGINAL: return 'm'; - case TRUST_FULLY: return 'f'; - case TRUST_ULTIMATE: return 'u'; - default: return '?'; - } -} - - -/* The strings here are similar to those in - pkclist.c:do_edit_ownertrust() */ -const char * -trust_value_to_string (unsigned int value) -{ - switch ((value & TRUST_MASK)) - { - case TRUST_UNKNOWN: return _("unknown"); - case TRUST_EXPIRED: return _("expired"); - case TRUST_UNDEFINED: return _("undefined"); - case TRUST_NEVER: return _("never"); - case TRUST_MARGINAL: return _("marginal"); - case TRUST_FULLY: return _("full"); - case TRUST_ULTIMATE: return _("ultimate"); - default: return "err"; - } -} - - -int -string_to_trust_value (const char *str) -{ - if (!ascii_strcasecmp (str, "undefined")) - return TRUST_UNDEFINED; - else if (!ascii_strcasecmp (str, "never")) - return TRUST_NEVER; - else if (!ascii_strcasecmp (str, "marginal")) - return TRUST_MARGINAL; - else if (!ascii_strcasecmp (str, "full")) - return TRUST_FULLY; - else if (!ascii_strcasecmp(str, "ultimate")) - return TRUST_ULTIMATE; - else - return -1; -} - - -const char * -uid_trust_string_fixed (ctrl_t ctrl, PKT_public_key *key, PKT_user_id *uid) -{ - if (!key && !uid) - { - /* TRANSLATORS: these strings are similar to those in - trust_value_to_string(), but are a fixed length. This is needed to - make attractive information listings where columns line up - properly. The value "10" should be the length of the strings you - choose to translate to. This is the length in printable columns. - It gets passed to atoi() so everything after the number is - essentially a comment and need not be translated. Either key and - uid are both NULL, or neither are NULL. */ - return _("10 translator see trust.c:uid_trust_string_fixed"); - } - else if(uid->flags.revoked || (key && key->flags.revoked)) - return _("[ revoked]"); - else if(uid->flags.expired) - return _("[ expired]"); - else if(key) - { - switch (get_validity (ctrl, NULL, key, uid, NULL, 0) & TRUST_MASK) - { - case TRUST_UNKNOWN: return _("[ unknown]"); - case TRUST_EXPIRED: return _("[ expired]"); - case TRUST_UNDEFINED: return _("[ undef ]"); - case TRUST_NEVER: return _("[ never ]"); - case TRUST_MARGINAL: return _("[marginal]"); - case TRUST_FULLY: return _("[ full ]"); - case TRUST_ULTIMATE: return _("[ultimate]"); - } - } - - return "err"; -} - - - -/* - * Return the assigned ownertrust value for the given public key. - * The key should be the primary key. - */ -unsigned int -get_ownertrust (ctrl_t ctrl, PKT_public_key *pk) -{ -#ifdef NO_TRUST_MODELS - (void)pk; - return TRUST_UNKNOWN; -#else - return tdb_get_ownertrust (ctrl, pk, 0); -#endif -} - - -/* - * Same as get_ownertrust but this takes the minimum ownertrust value - * into account, and will bump up the value as needed. NO_CREATE - * inhibits creation of a trustdb it that does not yet exists. - */ -static int -get_ownertrust_with_min (ctrl_t ctrl, PKT_public_key *pk, int no_create) -{ -#ifdef NO_TRUST_MODELS - (void)pk; - return TRUST_UNKNOWN; -#else - unsigned int otrust, otrust_min; - - /* Shortcut instead of doing the same twice in the two tdb_get - * functions: If the caller asked not to create a trustdb we call - * init_trustdb directly and allow it to fail with an error code for - * a non-existing trustdb. */ - if (no_create && init_trustdb (ctrl, 1)) - return TRUST_UNKNOWN; - - otrust = (tdb_get_ownertrust (ctrl, pk, no_create) & TRUST_MASK); - otrust_min = tdb_get_min_ownertrust (ctrl, pk, no_create); - if (otrust < otrust_min) - { - /* If the trust that the user has set is less than the trust - that was calculated from a trust signature chain, use the - higher of the two. We do this here and not in - get_ownertrust since the underlying ownertrust should not - really be set - just the appearance of the ownertrust. */ - - otrust = otrust_min; - } - - return otrust; -#endif -} - - -/* - * Same as get_ownertrust but return a trust letter instead of an - * value. This takes the minimum ownertrust value into account. If - * NO_CREATE is set, no efforts for creating a trustdb will be taken. - */ -int -get_ownertrust_info (ctrl_t ctrl, PKT_public_key *pk, int no_create) -{ - return trust_letter (get_ownertrust_with_min (ctrl, pk, no_create)); -} - - -/* - * Same as get_ownertrust but return a trust string instead of an - * value. This takes the minimum ownertrust value into account. If - * NO_CREATE is set, no efforts for creating a trustdb will be taken. - */ -const char * -get_ownertrust_string (ctrl_t ctrl, PKT_public_key *pk, int no_create) -{ - return trust_value_to_string (get_ownertrust_with_min (ctrl, pk, no_create)); -} - - -/* - * Set the trust value of the given public key to the new value. - * The key should be a primary one. - */ -void -update_ownertrust (ctrl_t ctrl, PKT_public_key *pk, unsigned int new_trust) -{ -#ifdef NO_TRUST_MODELS - (void)pk; - (void)new_trust; -#else - tdb_update_ownertrust (ctrl, pk, new_trust); -#endif -} - - -int -clear_ownertrusts (ctrl_t ctrl, PKT_public_key *pk) -{ -#ifdef NO_TRUST_MODELS - (void)pk; - return 0; -#else - return tdb_clear_ownertrusts (ctrl, pk); -#endif -} - - -void -revalidation_mark (ctrl_t ctrl) -{ -#ifndef NO_TRUST_MODELS - tdb_revalidation_mark (ctrl); -#endif -} - - -void -check_trustdb_stale (ctrl_t ctrl) -{ -#ifndef NO_TRUST_MODELS - tdb_check_trustdb_stale (ctrl); -#else - (void)ctrl; -#endif -} - - -void -check_or_update_trustdb (ctrl_t ctrl) -{ -#ifndef NO_TRUST_MODELS - tdb_check_or_update (ctrl); -#else - (void)ctrl; -#endif -} - - -/* - * Return the validity information for KB/PK (at least one must be - * non-NULL). If the namehash is not NULL, the validity of the - * corresponding user ID is returned, otherwise, a reasonable value - * for the entire key is returned. - */ -unsigned int -get_validity (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk, PKT_user_id *uid, - PKT_signature *sig, int may_ask) -{ - int rc; - unsigned int validity; - u32 kid[2]; - PKT_public_key *main_pk; - - if (kb && pk) - log_assert (keyid_cmp (pk_main_keyid (pk), - pk_main_keyid (kb->pkt->pkt.public_key)) == 0); - - if (! pk) - { - log_assert (kb); - pk = kb->pkt->pkt.public_key; - } - - if (uid) - namehash_from_uid (uid); - - keyid_from_pk (pk, kid); - if (pk->main_keyid[0] != kid[0] || pk->main_keyid[1] != kid[1]) - { - /* This is a subkey - get the mainkey. */ - if (kb) - main_pk = kb->pkt->pkt.public_key; - else - { - main_pk = xmalloc_clear (sizeof *main_pk); - rc = get_pubkey (ctrl, main_pk, pk->main_keyid); - if (rc) - { - char *tempkeystr = xstrdup (keystr (pk->main_keyid)); - log_error ("error getting main key %s of subkey %s: %s\n", - tempkeystr, keystr (kid), gpg_strerror (rc)); - xfree (tempkeystr); - validity = TRUST_UNKNOWN; - goto leave; - } - } - } - else - main_pk = pk; - -#ifdef NO_TRUST_MODELS - validity = TRUST_UNKNOWN; -#else - validity = tdb_get_validity_core (ctrl, kb, pk, uid, main_pk, sig, may_ask); -#endif - - leave: - /* Set some flags direct from the key */ - if (main_pk->flags.revoked) - validity |= TRUST_FLAG_REVOKED; - if (main_pk != pk && pk->flags.revoked) - validity |= TRUST_FLAG_SUB_REVOKED; - /* Note: expiration is a trust value and not a flag - don't know why - * I initially designed it that way. */ - if (main_pk->has_expired || pk->has_expired) - validity = ((validity & (~TRUST_MASK | TRUST_FLAG_PENDING_CHECK)) - | TRUST_EXPIRED); - - if (main_pk != pk && !kb) - free_public_key (main_pk); - return validity; -} - - -int -get_validity_info (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk, - PKT_user_id *uid) -{ - int trustlevel; - - if (kb && pk) - log_assert (keyid_cmp (pk_main_keyid (pk), - pk_main_keyid (kb->pkt->pkt.public_key)) == 0); - - if (! pk && kb) - pk = kb->pkt->pkt.public_key; - if (!pk) - return '?'; /* Just in case a NULL PK is passed. */ - - trustlevel = get_validity (ctrl, kb, pk, uid, NULL, 0); - if ((trustlevel & TRUST_FLAG_REVOKED)) - return 'r'; - return trust_letter (trustlevel); -} - - -const char * -get_validity_string (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid) -{ - int trustlevel; - - if (!pk) - return "err"; /* Just in case a NULL PK is passed. */ - - trustlevel = get_validity (ctrl, NULL, pk, uid, NULL, 0); - if ((trustlevel & TRUST_FLAG_REVOKED)) - return _("revoked"); - return trust_value_to_string (trustlevel); -} +#include "key-clean.h" - /* * Mark the signature of the given UID which are used to certify it. * To do this, we first revmove all signatures which are not valid and diff --git a/g10/key-clean.h b/g10/key-clean.h new file mode 100644 index 0000000..4dfd950 --- /dev/null +++ b/g10/key-clean.h @@ -0,0 +1,37 @@ +/* key-clean.h - Functions to clean a keyblock + * 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 . + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef GNUPG_G10_KEY_CLEAN_H +#define GNUPG_G10_KEY_CLEAN_H + +#include "gpg.h" + +void mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, + u32 *main_kid, struct key_item *klist, + u32 curtime, u32 *next_expire); + +void clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, + int noisy, int self_only, + int *uids_cleaned, int *sigs_cleaned); +void clean_key (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, + int *uids_cleaned,int *sigs_cleaned); + + +#endif /*GNUPG_G10_KEY_CLEAN_H*/ diff --git a/g10/keydb.h b/g10/keydb.h index ea0fa9d..9748e57 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -64,6 +64,20 @@ struct kbnode_struct { #define is_cloned_kbnode(a) ((a)->private_flag & 2) +/* + * A structure to store key identification as well as some stuff + * needed for key validation. + */ +struct key_item { + struct key_item *next; + unsigned int ownertrust,min_ownertrust; + byte trust_depth; + byte trust_value; + char *trust_regexp; + u32 kid[2]; +}; + + /* Bit flags used with build_pk_list. */ enum { @@ -133,6 +147,22 @@ enum }; +/* + * Check whether the signature SIG is in the klist K. + */ +static inline struct key_item * +is_in_klist (struct key_item *k, PKT_signature *sig) +{ + for (; k; k = k->next) + { + if (k->kid[0] == sig->keyid[0] && k->kid[1] == sig->keyid[1]) + return k; + } + return NULL; +} + + + /*-- keydb.c --*/ #define KEYDB_RESOURCE_FLAG_PRIMARY 2 /* The primary resource. */ diff --git a/g10/keyedit.c b/g10/keyedit.c index 00b4e72..9716ed9 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -49,6 +49,7 @@ #include "../common/host2net.h" #include "tofu.h" #include "key-check.h" +#include "key-clean.h" #include "keyedit.h" static void show_prefs (PKT_user_id * uid, PKT_signature * selfsig, diff --git a/g10/trust.c b/g10/trust.c index 6d4f0e7..bd1c894 100644 --- a/g10/trust.c +++ b/g10/trust.c @@ -437,391 +437,3 @@ get_validity_string (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid) return _("revoked"); return trust_value_to_string (trustlevel); } - - - -/* - * Mark the signature of the given UID which are used to certify it. - * To do this, we first revmove all signatures which are not valid and - * from the remain ones we look for the latest one. If this is not a - * certification revocation signature we mark the signature by setting - * node flag bit 8. Revocations are marked with flag 11, and sigs - * from unavailable keys are marked with flag 12. Note that flag bits - * 9 and 10 are used for internal purposes. - */ -void -mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, - u32 *main_kid, struct key_item *klist, - u32 curtime, u32 *next_expire) -{ - kbnode_t node; - PKT_signature *sig; - - /* First check all signatures. */ - for (node=uidnode->next; node; node = node->next) - { - int rc; - - node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12); - if (node->pkt->pkttype == PKT_USER_ID - || node->pkt->pkttype == PKT_PUBLIC_SUBKEY - || node->pkt->pkttype == PKT_SECRET_SUBKEY) - break; /* ready */ - if (node->pkt->pkttype != PKT_SIGNATURE) - continue; - sig = node->pkt->pkt.signature; - if (main_kid - && sig->keyid[0] == main_kid[0] && sig->keyid[1] == main_kid[1]) - continue; /* ignore self-signatures if we pass in a main_kid */ - if (!IS_UID_SIG(sig) && !IS_UID_REV(sig)) - continue; /* we only look at these signature classes */ - if(sig->sig_class>=0x11 && sig->sig_class<=0x13 && - sig->sig_class-0x10flag |= 1<<12; - continue; - } - node->flag |= 1<<9; - } - /* Reset the remaining flags. */ - for (; node; node = node->next) - node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12); - - /* kbnode flag usage: bit 9 is here set for signatures to consider, - * bit 10 will be set by the loop to keep track of keyIDs already - * processed, bit 8 will be set for the usable signatures, and bit - * 11 will be set for usable revocations. */ - - /* For each cert figure out the latest valid one. */ - for (node=uidnode->next; node; node = node->next) - { - KBNODE n, signode; - u32 kid[2]; - u32 sigdate; - - if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY - || node->pkt->pkttype == PKT_SECRET_SUBKEY) - break; - if ( !(node->flag & (1<<9)) ) - continue; /* not a node to look at */ - if ( (node->flag & (1<<10)) ) - continue; /* signature with a keyID already processed */ - node->flag |= (1<<10); /* mark this node as processed */ - sig = node->pkt->pkt.signature; - signode = node; - sigdate = sig->timestamp; - kid[0] = sig->keyid[0]; kid[1] = sig->keyid[1]; - - /* Now find the latest and greatest signature */ - for (n=uidnode->next; n; n = n->next) - { - if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY - || n->pkt->pkttype == PKT_SECRET_SUBKEY) - break; - if ( !(n->flag & (1<<9)) ) - continue; - if ( (n->flag & (1<<10)) ) - continue; /* shortcut already processed signatures */ - sig = n->pkt->pkt.signature; - if (kid[0] != sig->keyid[0] || kid[1] != sig->keyid[1]) - continue; - n->flag |= (1<<10); /* mark this node as processed */ - - /* If signode is nonrevocable and unexpired and n isn't, - then take signode (skip). It doesn't matter which is - older: if signode was older then we don't want to take n - as signode is nonrevocable. If n was older then we're - automatically fine. */ - - if(((IS_UID_SIG(signode->pkt->pkt.signature) && - !signode->pkt->pkt.signature->flags.revocable && - (signode->pkt->pkt.signature->expiredate==0 || - signode->pkt->pkt.signature->expiredate>curtime))) && - (!(IS_UID_SIG(n->pkt->pkt.signature) && - !n->pkt->pkt.signature->flags.revocable && - (n->pkt->pkt.signature->expiredate==0 || - n->pkt->pkt.signature->expiredate>curtime)))) - continue; - - /* If n is nonrevocable and unexpired and signode isn't, - then take n. Again, it doesn't matter which is older: if - n was older then we don't want to take signode as n is - nonrevocable. If signode was older then we're - automatically fine. */ - - if((!(IS_UID_SIG(signode->pkt->pkt.signature) && - !signode->pkt->pkt.signature->flags.revocable && - (signode->pkt->pkt.signature->expiredate==0 || - signode->pkt->pkt.signature->expiredate>curtime))) && - ((IS_UID_SIG(n->pkt->pkt.signature) && - !n->pkt->pkt.signature->flags.revocable && - (n->pkt->pkt.signature->expiredate==0 || - n->pkt->pkt.signature->expiredate>curtime)))) - { - signode = n; - sigdate = sig->timestamp; - continue; - } - - /* At this point, if it's newer, it goes in as the only - remaining possibilities are signode and n are both either - revocable or expired or both nonrevocable and unexpired. - If the timestamps are equal take the later ordered - packet, presuming that the key packets are hopefully in - their original order. */ - - if (sig->timestamp >= sigdate) - { - signode = n; - sigdate = sig->timestamp; - } - } - - sig = signode->pkt->pkt.signature; - if (IS_UID_SIG (sig)) - { /* this seems to be a usable one which is not revoked. - * Just need to check whether there is an expiration time, - * We do the expired certification after finding a suitable - * certification, the assumption is that a signator does not - * want that after the expiration of his certificate the - * system falls back to an older certification which has a - * different expiration time */ - const byte *p; - u32 expire; - - p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL ); - expire = p? sig->timestamp + buf32_to_u32(p) : 0; - - if (expire==0 || expire > curtime ) - { - signode->flag |= (1<<8); /* yeah, found a good cert */ - if (next_expire && expire && expire < *next_expire) - *next_expire = expire; - } - } - else - signode->flag |= (1<<11); - } -} - - -static int -clean_sigs_from_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, - int noisy, int self_only) -{ - int deleted = 0; - kbnode_t node; - u32 keyid[2]; - - log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY - || keyblock->pkt->pkttype == PKT_SECRET_KEY); - - keyid_from_pk (keyblock->pkt->pkt.public_key, keyid); - - /* Passing in a 0 for current time here means that we'll never weed - out an expired sig. This is correct behavior since we want to - keep the most recent expired sig in a series. */ - mark_usable_uid_certs (ctrl, keyblock, uidnode, NULL, NULL, 0, NULL); - - /* What we want to do here is remove signatures that are not - considered as part of the trust calculations. Thus, all invalid - signatures are out, as are any signatures that aren't the last of - a series of uid sigs or revocations It breaks down like this: - coming out of mark_usable_uid_certs, if a sig is unflagged, it is - not even a candidate. If a sig has flag 9 or 10, that means it - was selected as a candidate and vetted. If a sig has flag 8 it - is a usable signature. If a sig has flag 11 it is a usable - revocation. If a sig has flag 12 it was issued by an unavailable - key. "Usable" here means the most recent valid - signature/revocation in a series from a particular signer. - - Delete everything that isn't a usable uid sig (which might be - expired), a usable revocation, or a sig from an unavailable - key. */ - - for (node=uidnode->next; - node && node->pkt->pkttype==PKT_SIGNATURE; - node=node->next) - { - int keep; - - keep = self_only? (node->pkt->pkt.signature->keyid[0] == keyid[0] - && node->pkt->pkt.signature->keyid[1] == keyid[1]) : 1; - - /* Keep usable uid sigs ... */ - if ((node->flag & (1<<8)) && keep) - continue; - - /* ... and usable revocations... */ - if ((node->flag & (1<<11)) && keep) - continue; - - /* ... and sigs from unavailable keys. */ - /* disabled for now since more people seem to want sigs from - unavailable keys removed altogether. */ - /* - if(node->flag & (1<<12)) - continue; - */ - - /* Everything else we delete */ - - /* At this point, if 12 is set, the signing key was unavailable. - If 9 or 10 is set, it's superseded. Otherwise, it's - invalid. */ - - if (noisy) - log_info ("removing signature from key %s on user ID \"%s\": %s\n", - keystr (node->pkt->pkt.signature->keyid), - uidnode->pkt->pkt.user_id->name, - node->flag&(1<<12)? "key unavailable": - node->flag&(1<<9)? "signature superseded" - /* */ :"invalid signature" ); - - delete_kbnode (node); - deleted++; - } - - return deleted; -} - - -/* This is substantially easier than clean_sigs_from_uid since we just - have to establish if the uid has a valid self-sig, is not revoked, - and is not expired. Note that this does not take into account - whether the uid has a trust path to it - just whether the keyholder - themselves has certified the uid. Returns true if the uid was - compacted. To "compact" a user ID, we simply remove ALL signatures - except the self-sig that caused the user ID to be remove-worthy. - We don't actually remove the user ID packet itself since it might - be resurrected in a later merge. Note that this function requires - that the caller has already done a merge_keys_and_selfsig(). - - TODO: change the import code to allow importing a uid with only a - revocation if the uid already exists on the keyring. */ - -static int -clean_uid_from_key (kbnode_t keyblock, kbnode_t uidnode, int noisy) -{ - kbnode_t node; - PKT_user_id *uid = uidnode->pkt->pkt.user_id; - int deleted = 0; - - log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY - || keyblock->pkt->pkttype == PKT_SECRET_KEY); - log_assert (uidnode->pkt->pkttype==PKT_USER_ID); - - /* Skip valid user IDs, compacted user IDs, and non-self-signed user - IDs if --allow-non-selfsigned-uid is set. */ - if (uid->created - || uid->flags.compacted - || (!uid->flags.expired && !uid->flags.revoked && opt.allow_non_selfsigned_uid)) - return 0; - - for (node=uidnode->next; - node && node->pkt->pkttype == PKT_SIGNATURE; - node=node->next) - { - if (!node->pkt->pkt.signature->flags.chosen_selfsig) - { - delete_kbnode (node); - deleted = 1; - uidnode->pkt->pkt.user_id->flags.compacted = 1; - } - } - - if (noisy) - { - const char *reason; - char *user = utf8_to_native (uid->name, uid->len, 0); - - if (uid->flags.revoked) - reason = _("revoked"); - else if (uid->flags.expired) - reason = _("expired"); - else - reason = _("invalid"); - - log_info ("compacting user ID \"%s\" on key %s: %s\n", - user, keystr_from_pk (keyblock->pkt->pkt.public_key), - reason); - - xfree (user); - } - - return deleted; -} - - -/* Needs to be called after a merge_keys_and_selfsig() */ -void -clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, - int noisy, int self_only, int *uids_cleaned, int *sigs_cleaned) -{ - int dummy = 0; - - log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY - || keyblock->pkt->pkttype == PKT_SECRET_KEY); - log_assert (uidnode->pkt->pkttype==PKT_USER_ID); - - if (!uids_cleaned) - uids_cleaned = &dummy; - - if (!sigs_cleaned) - sigs_cleaned = &dummy; - - /* Do clean_uid_from_key first since if it fires off, we don't have - to bother with the other. */ - *uids_cleaned += clean_uid_from_key (keyblock, uidnode, noisy); - if (!uidnode->pkt->pkt.user_id->flags.compacted) - *sigs_cleaned += clean_sigs_from_uid (ctrl, keyblock, uidnode, - noisy, self_only); -} - - -/* NB: This function marks the deleted nodes only and the caller is - * responsible to skip or remove them. */ -void -clean_key (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, - int *uids_cleaned, int *sigs_cleaned) -{ - kbnode_t node; - - merge_keys_and_selfsig (ctrl, keyblock); - - for (node = keyblock->next; - node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY - || node->pkt->pkttype == PKT_SECRET_SUBKEY); - node = node->next) - { - if (node->pkt->pkttype == PKT_USER_ID) - clean_one_uid (ctrl, keyblock, node, noisy, self_only, - uids_cleaned, sigs_cleaned); - } - - /* Remove bogus subkey binding signatures: The only signatures - * allowed are of class 0x18 and 0x28. */ - log_assert (!node || (node->pkt->pkttype == PKT_PUBLIC_SUBKEY - || node->pkt->pkttype == PKT_SECRET_SUBKEY)); - for (; node; node = node->next) - { - if (is_deleted_kbnode (node)) - continue; - if (node->pkt->pkttype == PKT_SIGNATURE - && !(IS_SUBKEY_SIG (node->pkt->pkt.signature) - || IS_SUBKEY_REV (node->pkt->pkt.signature))) - { - delete_kbnode (node); - if (sigs_cleaned) - ++*sigs_cleaned; - } - } -} diff --git a/g10/trustdb.c b/g10/trustdb.c index 2c2d239..8ef6db5 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -41,6 +41,7 @@ #include "tdbio.h" #include "trustdb.h" #include "tofu.h" +#include "key-clean.h" typedef struct key_item **KeyHashTable; /* see new_key_hash_table() */ diff --git a/g10/trustdb.h b/g10/trustdb.h index 4bc4ca9..d52fc53 100644 --- a/g10/trustdb.h +++ b/g10/trustdb.h @@ -46,36 +46,6 @@ #define NAMEHASH_LEN 20 -/* - * A structure to store key identification as well as some stuff needed - * for validation - */ -struct key_item { - struct key_item *next; - unsigned int ownertrust,min_ownertrust; - byte trust_depth; - byte trust_value; - char *trust_regexp; - u32 kid[2]; -}; - - -/* - * Check whether the signature SIG is in the klist K. - */ -static inline struct key_item * -is_in_klist (struct key_item *k, PKT_signature *sig) -{ - for (; k; k = k->next) - { - if (k->kid[0] == sig->keyid[0] && k->kid[1] == sig->keyid[1]) - return k; - } - return NULL; -} - - - /*-- trust.c --*/ int cache_disabled_value (ctrl_t ctrl, PKT_public_key *pk); void register_trusted_keyid (u32 *keyid); @@ -103,17 +73,6 @@ int get_validity_info (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk, const char *get_validity_string (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid); -void mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, - u32 *main_kid, struct key_item *klist, - u32 curtime, u32 *next_expire); - -void clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, - int noisy, int self_only, - int *uids_cleaned, int *sigs_cleaned); -void clean_key (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, - int *uids_cleaned,int *sigs_cleaned); - - /*-- trustdb.c --*/ void tdb_register_trusted_keyid (u32 *keyid); ----------------------------------------------------------------------- Summary of changes: g10/Makefile.am | 1 + g10/export.c | 19 +- g10/import.c | 31 ++- g10/{trust.c => key-clean.c} | 544 ++++++++++--------------------------------- g10/key-clean.h | 52 +++++ g10/keydb.h | 30 +++ g10/keyedit.c | 1 + g10/trust.c | 388 ------------------------------ g10/trustdb.c | 1 + g10/trustdb.h | 41 ---- 10 files changed, 249 insertions(+), 859 deletions(-) copy g10/{trust.c => key-clean.c} (58%) create mode 100644 g10/key-clean.h hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 9 10:45:09 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Mon, 09 Jul 2018 10:45:09 +0200 Subject: [git] GnuPG - branch, STABLE-BRANCH-2-2, updated. gnupg-2.2.8-27-g8055f18 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, STABLE-BRANCH-2-2 has been updated via 8055f186a32e628028de897b7ee4705cd8e999b7 (commit) via 046276db3a04f1907ddcf77c3771832613918226 (commit) via 40bf383f72b5629de739e30c9c35bbcb628273e8 (commit) from b4599a0449ead7dc5c0d922aa78b6168e625e15e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 8055f186a32e628028de897b7ee4705cd8e999b7 Author: Werner Koch Date: Mon Jul 9 09:49:09 2018 +0200 gpg: Let export-clean remove expired subkeys. * g10/key-clean.h (KEY_CLEAN_NONE, KEY_CLEAN_INVALID) (KEY_CLEAN_ENCR, KEY_CLEAN_AUTHENCR, KEY_CLEAN_ALL): New. * g10/key-clean.c (clean_one_subkey): New. (clean_all_subkeys): Add arg CLEAN_LEVEL. * g10/import.c (import_one): Call clean_all_subkeys with KEY_CLEAN_NONE. * g10/export.c (do_export_stream): Call clean_all_subkeys depedning on the export clean options. -- GnuPG-bug-id: 3622 Signed-off-by: Werner Koch (cherry picked from commit c2fd65ec8498a08ee36ca52d99b6b014f6db8d93) diff --git a/g10/export.c b/g10/export.c index 21ff23c..e94e959 100644 --- a/g10/export.c +++ b/g10/export.c @@ -2003,15 +2003,18 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, } /* Always do the cleaning on the public key part if requested. - * Note that both export-clean and export-minimal only apply to - * UID sigs (0x10, 0x11, 0x12, and 0x13). A designated - * revocation is never stripped, even with export-minimal set. */ + * A designated revocation is never stripped, even with + * export-minimal set. */ if ((options & EXPORT_CLEAN)) { merge_keys_and_selfsig (ctrl, keyblock); clean_all_uids (ctrl, keyblock, opt.verbose, (options&EXPORT_MINIMAL), NULL, NULL); - clean_all_subkeys (ctrl, keyblock, opt.verbose, NULL, NULL); + clean_all_subkeys (ctrl, keyblock, opt.verbose, + (options&EXPORT_MINIMAL)? KEY_CLEAN_ALL + /**/ : KEY_CLEAN_AUTHENCR, + NULL, NULL); + commit_kbnode (&keyblock); } if (export_keep_uid) diff --git a/g10/import.c b/g10/import.c index 6b6411c..6dad8ee 100644 --- a/g10/import.c +++ b/g10/import.c @@ -1746,7 +1746,8 @@ import_one (ctrl_t ctrl, merge_keys_and_selfsig (ctrl, keyblock); clean_all_uids (ctrl, keyblock, opt.verbose, (options&IMPORT_MINIMAL), NULL, NULL); - clean_all_subkeys (ctrl, keyblock, opt.verbose, NULL, NULL); + clean_all_subkeys (ctrl, keyblock, opt.verbose, KEY_CLEAN_NONE, + NULL, NULL); } clear_kbnode_flags( keyblock ); @@ -1892,7 +1893,8 @@ import_one (ctrl_t ctrl, merge_keys_and_selfsig (ctrl, keyblock); clean_all_uids (ctrl, keyblock, opt.verbose, (options&IMPORT_MINIMAL), &n_uids_cleaned,&n_sigs_cleaned); - clean_all_subkeys (ctrl, keyblock, opt.verbose, NULL, NULL); + clean_all_subkeys (ctrl, keyblock, opt.verbose, KEY_CLEAN_NONE, + NULL, NULL); } /* Unless we are in restore mode apply meta data to the @@ -1983,7 +1985,8 @@ import_one (ctrl_t ctrl, clean_all_uids (ctrl, keyblock_orig, opt.verbose, (options&IMPORT_MINIMAL), &n_uids_cleaned,&n_sigs_cleaned); - clean_all_subkeys (ctrl, keyblock_orig, opt.verbose, NULL, NULL); + clean_all_subkeys (ctrl, keyblock_orig, opt.verbose, KEY_CLEAN_NONE, + NULL, NULL); } if (n_uids || n_sigs || n_subk || n_sigs_cleaned || n_uids_cleaned) diff --git a/g10/key-clean.c b/g10/key-clean.c index 10478a4..097ca17 100644 --- a/g10/key-clean.c +++ b/g10/key-clean.c @@ -408,24 +408,101 @@ clean_all_uids (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, } +/* Helper for clean_all_subkeys. */ +static int +clean_one_subkey (ctrl_t ctrl, kbnode_t subkeynode, int noisy, int clean_level) +{ + kbnode_t node; + PKT_public_key *pk = subkeynode->pkt->pkt.public_key; + unsigned int use = pk->pubkey_usage; + int do_clean = 0; + + (void)ctrl; + (void)noisy; + + log_assert (subkeynode->pkt->pkttype == PKT_PUBLIC_SUBKEY + || subkeynode->pkt->pkttype == PKT_SECRET_SUBKEY); + + if (DBG_LOOKUP) + log_debug ("\tchecking subkey %08lX [%c%c%c%c%c]\n", + (ulong) keyid_from_pk (pk, NULL), + (use & PUBKEY_USAGE_ENC)? 'e':'-', + (use & PUBKEY_USAGE_SIG)? 's':'-', + (use & PUBKEY_USAGE_CERT)? 'c':'-', + (use & PUBKEY_USAGE_AUTH)? 'a':'-', + (use & PUBKEY_USAGE_UNKNOWN)? '?':'-'); + + if (!pk->flags.valid) + { + if (DBG_LOOKUP) + log_debug ("\tsubkey not valid\n"); + if (clean_level == KEY_CLEAN_INVALID) + do_clean = 1; + } + if (pk->has_expired) + { + if (DBG_LOOKUP) + log_debug ("\tsubkey has expired\n"); + if (clean_level == KEY_CLEAN_ALL) + do_clean = 1; + else if (clean_level == KEY_CLEAN_AUTHENCR + && (use & (PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH)) + && !(use & (PUBKEY_USAGE_SIG | PUBKEY_USAGE_CERT))) + do_clean = 1; + else if (clean_level == KEY_CLEAN_ENCR + && (use & PUBKEY_USAGE_ENC) + && !(use & (PUBKEY_USAGE_SIG | PUBKEY_USAGE_CERT + | PUBKEY_USAGE_AUTH))) + do_clean = 1; + } + if (pk->flags.revoked) + { + if (DBG_LOOKUP) + log_debug ("\tsubkey has been revoked (keeping)\n"); + /* Avoid any cleaning because revocations are important. */ + do_clean = 0; + } + if (!do_clean) + return 0; + + if (DBG_LOOKUP) + log_debug ("\t=> removing this subkey\n"); + + delete_kbnode (subkeynode); + for (node = subkeynode->next; + node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY + || node->pkt->pkttype == PKT_SECRET_SUBKEY); + node = node->next) + delete_kbnode (node); + + return 1; +} + + /* This function only marks the deleted nodes and the caller is * responsible to skip or remove them. Needs to be called after a - * merge_keys_and_selfsig. */ + * merge_keys_and_selfsig. CLEAN_LEVEL is one of the KEY_CLEAN_* + * values. */ void -clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, +clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, int clean_level, int *subkeys_cleaned, int *sigs_cleaned) { - kbnode_t node; + kbnode_t first_subkey, node; + + if (DBG_LOOKUP) + log_debug ("clean_all_subkeys: checking key %08lX\n", + (ulong) keyid_from_pk (keyblock->pkt->pkt.public_key, NULL)); for (node = keyblock->next; node; node = node->next) if (!is_deleted_kbnode (node) && (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY)) break; + first_subkey = node; /* Remove bogus subkey binding signatures: The only signatures * allowed are of class 0x18 and 0x28. */ - for (; node; node = node->next) + for (node = first_subkey; node; node = node->next) { if (is_deleted_kbnode (node)) continue; @@ -438,4 +515,21 @@ clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, ++*sigs_cleaned; } } + + /* Do the selected cleaning. */ + if (clean_level > KEY_CLEAN_NONE) + { + for (node = first_subkey; node; node = node->next) + { + if (is_deleted_kbnode (node)) + continue; + if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY + || node->pkt->pkttype == PKT_SECRET_SUBKEY) + if (clean_one_subkey (ctrl, node, noisy, clean_level)) + { + if (subkeys_cleaned) + ++*subkeys_cleaned; + } + } + } } diff --git a/g10/key-clean.h b/g10/key-clean.h index 6938430..a0fb769 100644 --- a/g10/key-clean.h +++ b/g10/key-clean.h @@ -23,6 +23,18 @@ #include "gpg.h" +/* No explict cleaning. */ +#define KEY_CLEAN_NONE 0 +/* Remove only invalid subkeys (ie. missing key-bindings) */ +#define KEY_CLEAN_INVALID 1 +/* Remove expired encryption keys */ +#define KEY_CLEAN_ENCR 2 +/* Remove expired authentication and encryption keys. */ +#define KEY_CLEAN_AUTHENCR 3 +/* Remove all expired subkeys. */ +#define KEY_CLEAN_ALL 4 + + void mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, u32 *main_kid, struct key_item *klist, u32 curtime, u32 *next_expire); @@ -32,7 +44,8 @@ void clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, int *uids_cleaned, int *sigs_cleaned); void clean_all_uids (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, int *uids_cleaned,int *sigs_cleaned); -void clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, +void clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, + int noisy, int clean_level, int *subkeys_cleaned, int *sigs_cleaned); commit 046276db3a04f1907ddcf77c3771832613918226 Author: Werner Koch Date: Fri Jul 6 11:48:38 2018 +0200 gpg: Split key cleaning function for clarity. * g10/key-clean.c (clean_key): Rename to clean_all_uids and split subkey cleaning into ... (clean_all_subkeys): new. Call that always after the former clean_key invocations. -- Note that the clean_all_subkeys function will later be extended. Signed-off-by: Werner Koch (cherry picked from commit 6c3567196f7e72552f326ce07dccbcce31926e5d) diff --git a/g10/export.c b/g10/export.c index 44cf075..21ff23c 100644 --- a/g10/export.c +++ b/g10/export.c @@ -2007,8 +2007,12 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, * UID sigs (0x10, 0x11, 0x12, and 0x13). A designated * revocation is never stripped, even with export-minimal set. */ if ((options & EXPORT_CLEAN)) - clean_key (ctrl, keyblock, opt.verbose, - (options&EXPORT_MINIMAL), NULL, NULL); + { + merge_keys_and_selfsig (ctrl, keyblock); + clean_all_uids (ctrl, keyblock, opt.verbose, + (options&EXPORT_MINIMAL), NULL, NULL); + clean_all_subkeys (ctrl, keyblock, opt.verbose, NULL, NULL); + } if (export_keep_uid) { diff --git a/g10/import.c b/g10/import.c index fa7fc1f..6b6411c 100644 --- a/g10/import.c +++ b/g10/import.c @@ -1741,9 +1741,13 @@ import_one (ctrl_t ctrl, that we have to clean later. This has no practical impact on the end result, but does result in less logging which might confuse the user. */ - if (options&IMPORT_CLEAN) - clean_key (ctrl, keyblock, - opt.verbose, (options&IMPORT_MINIMAL), NULL, NULL); + if ((options & IMPORT_CLEAN)) + { + merge_keys_and_selfsig (ctrl, keyblock); + clean_all_uids (ctrl, keyblock, + opt.verbose, (options&IMPORT_MINIMAL), NULL, NULL); + clean_all_subkeys (ctrl, keyblock, opt.verbose, NULL, NULL); + } clear_kbnode_flags( keyblock ); @@ -1884,8 +1888,12 @@ import_one (ctrl_t ctrl, log_info (_("writing to '%s'\n"), keydb_get_resource_name (hd) ); if ((options & IMPORT_CLEAN)) - clean_key (ctrl, keyblock, opt.verbose, (options&IMPORT_MINIMAL), - &n_uids_cleaned,&n_sigs_cleaned); + { + merge_keys_and_selfsig (ctrl, keyblock); + clean_all_uids (ctrl, keyblock, opt.verbose, (options&IMPORT_MINIMAL), + &n_uids_cleaned,&n_sigs_cleaned); + clean_all_subkeys (ctrl, keyblock, opt.verbose, NULL, NULL); + } /* Unless we are in restore mode apply meta data to the * keyblock. Note that this will never change the first packet @@ -1970,8 +1978,13 @@ import_one (ctrl_t ctrl, goto leave; if ((options & IMPORT_CLEAN)) - clean_key (ctrl, keyblock_orig, opt.verbose, (options&IMPORT_MINIMAL), - &n_uids_cleaned,&n_sigs_cleaned); + { + merge_keys_and_selfsig (ctrl, keyblock_orig); + clean_all_uids (ctrl, keyblock_orig, opt.verbose, + (options&IMPORT_MINIMAL), + &n_uids_cleaned,&n_sigs_cleaned); + clean_all_subkeys (ctrl, keyblock_orig, opt.verbose, NULL, NULL); + } if (n_uids || n_sigs || n_subk || n_sigs_cleaned || n_uids_cleaned) { diff --git a/g10/key-clean.c b/g10/key-clean.c index d022ff4..10478a4 100644 --- a/g10/key-clean.c +++ b/g10/key-clean.c @@ -383,15 +383,14 @@ clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, /* NB: This function marks the deleted nodes only and the caller is - * responsible to skip or remove them. */ + * responsible to skip or remove them. Needs to be called after a + * merge_keys_and_selfsig(). */ void -clean_key (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, - int *uids_cleaned, int *sigs_cleaned) +clean_all_uids (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, + int *uids_cleaned, int *sigs_cleaned) { kbnode_t node; - merge_keys_and_selfsig (ctrl, keyblock); - for (node = keyblock->next; node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY); @@ -406,6 +405,26 @@ clean_key (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, * allowed are of class 0x18 and 0x28. */ log_assert (!node || (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY)); +} + + +/* This function only marks the deleted nodes and the caller is + * responsible to skip or remove them. Needs to be called after a + * merge_keys_and_selfsig. */ +void +clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, + int *subkeys_cleaned, int *sigs_cleaned) +{ + kbnode_t node; + + for (node = keyblock->next; node; node = node->next) + if (!is_deleted_kbnode (node) + && (node->pkt->pkttype == PKT_PUBLIC_SUBKEY + || node->pkt->pkttype == PKT_SECRET_SUBKEY)) + break; + + /* Remove bogus subkey binding signatures: The only signatures + * allowed are of class 0x18 and 0x28. */ for (; node; node = node->next) { if (is_deleted_kbnode (node)) diff --git a/g10/key-clean.h b/g10/key-clean.h index 4dfd950..6938430 100644 --- a/g10/key-clean.h +++ b/g10/key-clean.h @@ -30,8 +30,10 @@ void mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, void clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, int noisy, int self_only, int *uids_cleaned, int *sigs_cleaned); -void clean_key (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, - int *uids_cleaned,int *sigs_cleaned); +void clean_all_uids (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, + int *uids_cleaned,int *sigs_cleaned); +void clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, + int *subkeys_cleaned, int *sigs_cleaned); #endif /*GNUPG_G10_KEY_CLEAN_H*/ commit 40bf383f72b5629de739e30c9c35bbcb628273e8 Author: Werner Koch Date: Fri Jul 6 11:40:16 2018 +0200 gpg: Move key cleaning functions to a separate file. * g10/trust.c (mark_usable_uid_certs, clean_sigs_from_uid) (clean_uid_from_key, clean_one_uid, clean_key): Move to ... * g10/key-clean.c: new file. * g10/key-clean.h: New. * g10/Makefile.am (gpg_sources): Add new files. * g10/export.c, g10/import.c, g10/keyedit.c, g10/trustdb.c: Include new header. * g10/trustdb.h (struct key_item, is_in_klist): Move to ... * g10/keydb.h: here. -- Signed-off-by: Werner Koch (cherry picked from commit 135e46ea480d749b8a9692f71d4d0bfdadd8ee2f) diff --git a/g10/Makefile.am b/g10/Makefile.am index cc4ef5c..1da60ce 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -151,6 +151,7 @@ gpg_sources = server.c \ trust.c $(trust_source) $(tofu_source) \ $(card_source) \ exec.c exec.h \ + key-clean.c key-clean.h \ key-check.c key-check.h gpg_SOURCES = gpg.c \ diff --git a/g10/export.c b/g10/export.c index c538dc1..44cf075 100644 --- a/g10/export.c +++ b/g10/export.c @@ -41,6 +41,8 @@ #include "../common/init.h" #include "trustdb.h" #include "call-agent.h" +#include "key-clean.h" + /* An object to keep track of subkeys. */ struct subkey_list_s diff --git a/g10/import.c b/g10/import.c index b43060d..fa7fc1f 100644 --- a/g10/import.c +++ b/g10/import.c @@ -41,6 +41,7 @@ #include "../common/init.h" #include "../common/mbox-util.h" #include "key-check.h" +#include "key-clean.h" struct import_stats_s diff --git a/g10/trust.c b/g10/key-clean.c similarity index 58% copy from g10/trust.c copy to g10/key-clean.c index 6d4f0e7..d022ff4 100644 --- a/g10/trust.c +++ b/g10/key-clean.c @@ -1,7 +1,6 @@ -/* trust.c - High level trust functions - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, - * 2008, 2012 Free Software Foundation, Inc. - * Copyright (C) 2014 Werner Koch +/* key-clean.c - Functions to clean a keyblock + * Copyright (C) 1998-2008, 2010-2011 Free Software Foundation, Inc. + * Copyright (C) 2014, 2016-2018 Werner Koch * * This file is part of GnuPG. * @@ -17,6 +16,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see . + * SPDX-License-Identifier: GPL-3.0-or-later */ #include @@ -27,419 +27,14 @@ #include "gpg.h" #include "keydb.h" #include "../common/util.h" +#include "../common/host2net.h" +#include "../common/i18n.h" #include "options.h" #include "packet.h" #include "main.h" -#include "../common/i18n.h" -#include "trustdb.h" -#include "../common/host2net.h" - - -/* Return true if key is disabled. Note that this is usually used via - the pk_is_disabled macro. */ -int -cache_disabled_value (ctrl_t ctrl, PKT_public_key *pk) -{ -#ifdef NO_TRUST_MODELS - (void)pk; - return 0; -#else - return tdb_cache_disabled_value (ctrl, pk); -#endif -} - - -void -register_trusted_keyid (u32 *keyid) -{ -#ifdef NO_TRUST_MODELS - (void)keyid; -#else - tdb_register_trusted_keyid (keyid); -#endif -} - - -void -register_trusted_key (const char *string) -{ -#ifdef NO_TRUST_MODELS - (void)string; -#else - - /* Some users have conf files with entries like - * trusted-key 0x1234567812345678 # foo - * That is obviously wrong. Before fixing bug#1206 trailing garbage - * on a key specification if was ignored. We detect the above use case - * here and cut off the junk-looking-like-a comment. */ - if (strchr (string, '#')) - { - char *buf; - - buf = xtrystrdup (string); - if (buf) - { - *strchr (buf, '#') = 0; - tdb_register_trusted_key (buf); - xfree (buf); - return; - } - } - - tdb_register_trusted_key (string); -#endif -} - - - -/* - * This function returns a letter for a trust value. Trust flags - * are ignored. - */ -static int -trust_letter (unsigned int value) -{ - switch( (value & TRUST_MASK) ) - { - case TRUST_UNKNOWN: return '-'; - case TRUST_EXPIRED: return 'e'; - case TRUST_UNDEFINED: return 'q'; - case TRUST_NEVER: return 'n'; - case TRUST_MARGINAL: return 'm'; - case TRUST_FULLY: return 'f'; - case TRUST_ULTIMATE: return 'u'; - default: return '?'; - } -} - - -/* The strings here are similar to those in - pkclist.c:do_edit_ownertrust() */ -const char * -trust_value_to_string (unsigned int value) -{ - switch ((value & TRUST_MASK)) - { - case TRUST_UNKNOWN: return _("unknown"); - case TRUST_EXPIRED: return _("expired"); - case TRUST_UNDEFINED: return _("undefined"); - case TRUST_NEVER: return _("never"); - case TRUST_MARGINAL: return _("marginal"); - case TRUST_FULLY: return _("full"); - case TRUST_ULTIMATE: return _("ultimate"); - default: return "err"; - } -} - - -int -string_to_trust_value (const char *str) -{ - if (!ascii_strcasecmp (str, "undefined")) - return TRUST_UNDEFINED; - else if (!ascii_strcasecmp (str, "never")) - return TRUST_NEVER; - else if (!ascii_strcasecmp (str, "marginal")) - return TRUST_MARGINAL; - else if (!ascii_strcasecmp (str, "full")) - return TRUST_FULLY; - else if (!ascii_strcasecmp(str, "ultimate")) - return TRUST_ULTIMATE; - else - return -1; -} - - -const char * -uid_trust_string_fixed (ctrl_t ctrl, PKT_public_key *key, PKT_user_id *uid) -{ - if (!key && !uid) - { - /* TRANSLATORS: these strings are similar to those in - trust_value_to_string(), but are a fixed length. This is needed to - make attractive information listings where columns line up - properly. The value "10" should be the length of the strings you - choose to translate to. This is the length in printable columns. - It gets passed to atoi() so everything after the number is - essentially a comment and need not be translated. Either key and - uid are both NULL, or neither are NULL. */ - return _("10 translator see trust.c:uid_trust_string_fixed"); - } - else if(uid->flags.revoked || (key && key->flags.revoked)) - return _("[ revoked]"); - else if(uid->flags.expired) - return _("[ expired]"); - else if(key) - { - switch (get_validity (ctrl, NULL, key, uid, NULL, 0) & TRUST_MASK) - { - case TRUST_UNKNOWN: return _("[ unknown]"); - case TRUST_EXPIRED: return _("[ expired]"); - case TRUST_UNDEFINED: return _("[ undef ]"); - case TRUST_NEVER: return _("[ never ]"); - case TRUST_MARGINAL: return _("[marginal]"); - case TRUST_FULLY: return _("[ full ]"); - case TRUST_ULTIMATE: return _("[ultimate]"); - } - } - - return "err"; -} - - - -/* - * Return the assigned ownertrust value for the given public key. - * The key should be the primary key. - */ -unsigned int -get_ownertrust (ctrl_t ctrl, PKT_public_key *pk) -{ -#ifdef NO_TRUST_MODELS - (void)pk; - return TRUST_UNKNOWN; -#else - return tdb_get_ownertrust (ctrl, pk, 0); -#endif -} - - -/* - * Same as get_ownertrust but this takes the minimum ownertrust value - * into account, and will bump up the value as needed. NO_CREATE - * inhibits creation of a trustdb it that does not yet exists. - */ -static int -get_ownertrust_with_min (ctrl_t ctrl, PKT_public_key *pk, int no_create) -{ -#ifdef NO_TRUST_MODELS - (void)pk; - return TRUST_UNKNOWN; -#else - unsigned int otrust, otrust_min; - - /* Shortcut instead of doing the same twice in the two tdb_get - * functions: If the caller asked not to create a trustdb we call - * init_trustdb directly and allow it to fail with an error code for - * a non-existing trustdb. */ - if (no_create && init_trustdb (ctrl, 1)) - return TRUST_UNKNOWN; - - otrust = (tdb_get_ownertrust (ctrl, pk, no_create) & TRUST_MASK); - otrust_min = tdb_get_min_ownertrust (ctrl, pk, no_create); - if (otrust < otrust_min) - { - /* If the trust that the user has set is less than the trust - that was calculated from a trust signature chain, use the - higher of the two. We do this here and not in - get_ownertrust since the underlying ownertrust should not - really be set - just the appearance of the ownertrust. */ - - otrust = otrust_min; - } - - return otrust; -#endif -} - - -/* - * Same as get_ownertrust but return a trust letter instead of an - * value. This takes the minimum ownertrust value into account. If - * NO_CREATE is set, no efforts for creating a trustdb will be taken. - */ -int -get_ownertrust_info (ctrl_t ctrl, PKT_public_key *pk, int no_create) -{ - return trust_letter (get_ownertrust_with_min (ctrl, pk, no_create)); -} - - -/* - * Same as get_ownertrust but return a trust string instead of an - * value. This takes the minimum ownertrust value into account. If - * NO_CREATE is set, no efforts for creating a trustdb will be taken. - */ -const char * -get_ownertrust_string (ctrl_t ctrl, PKT_public_key *pk, int no_create) -{ - return trust_value_to_string (get_ownertrust_with_min (ctrl, pk, no_create)); -} - - -/* - * Set the trust value of the given public key to the new value. - * The key should be a primary one. - */ -void -update_ownertrust (ctrl_t ctrl, PKT_public_key *pk, unsigned int new_trust) -{ -#ifdef NO_TRUST_MODELS - (void)pk; - (void)new_trust; -#else - tdb_update_ownertrust (ctrl, pk, new_trust); -#endif -} - - -int -clear_ownertrusts (ctrl_t ctrl, PKT_public_key *pk) -{ -#ifdef NO_TRUST_MODELS - (void)pk; - return 0; -#else - return tdb_clear_ownertrusts (ctrl, pk); -#endif -} - - -void -revalidation_mark (ctrl_t ctrl) -{ -#ifndef NO_TRUST_MODELS - tdb_revalidation_mark (ctrl); -#endif -} - - -void -check_trustdb_stale (ctrl_t ctrl) -{ -#ifndef NO_TRUST_MODELS - tdb_check_trustdb_stale (ctrl); -#else - (void)ctrl; -#endif -} - - -void -check_or_update_trustdb (ctrl_t ctrl) -{ -#ifndef NO_TRUST_MODELS - tdb_check_or_update (ctrl); -#else - (void)ctrl; -#endif -} - - -/* - * Return the validity information for KB/PK (at least one must be - * non-NULL). If the namehash is not NULL, the validity of the - * corresponding user ID is returned, otherwise, a reasonable value - * for the entire key is returned. - */ -unsigned int -get_validity (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk, PKT_user_id *uid, - PKT_signature *sig, int may_ask) -{ - int rc; - unsigned int validity; - u32 kid[2]; - PKT_public_key *main_pk; - - if (kb && pk) - log_assert (keyid_cmp (pk_main_keyid (pk), - pk_main_keyid (kb->pkt->pkt.public_key)) == 0); - - if (! pk) - { - log_assert (kb); - pk = kb->pkt->pkt.public_key; - } - - if (uid) - namehash_from_uid (uid); - - keyid_from_pk (pk, kid); - if (pk->main_keyid[0] != kid[0] || pk->main_keyid[1] != kid[1]) - { - /* This is a subkey - get the mainkey. */ - if (kb) - main_pk = kb->pkt->pkt.public_key; - else - { - main_pk = xmalloc_clear (sizeof *main_pk); - rc = get_pubkey (ctrl, main_pk, pk->main_keyid); - if (rc) - { - char *tempkeystr = xstrdup (keystr (pk->main_keyid)); - log_error ("error getting main key %s of subkey %s: %s\n", - tempkeystr, keystr (kid), gpg_strerror (rc)); - xfree (tempkeystr); - validity = TRUST_UNKNOWN; - goto leave; - } - } - } - else - main_pk = pk; - -#ifdef NO_TRUST_MODELS - validity = TRUST_UNKNOWN; -#else - validity = tdb_get_validity_core (ctrl, kb, pk, uid, main_pk, sig, may_ask); -#endif - - leave: - /* Set some flags direct from the key */ - if (main_pk->flags.revoked) - validity |= TRUST_FLAG_REVOKED; - if (main_pk != pk && pk->flags.revoked) - validity |= TRUST_FLAG_SUB_REVOKED; - /* Note: expiration is a trust value and not a flag - don't know why - * I initially designed it that way. */ - if (main_pk->has_expired || pk->has_expired) - validity = ((validity & (~TRUST_MASK | TRUST_FLAG_PENDING_CHECK)) - | TRUST_EXPIRED); - - if (main_pk != pk && !kb) - free_public_key (main_pk); - return validity; -} - - -int -get_validity_info (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk, - PKT_user_id *uid) -{ - int trustlevel; - - if (kb && pk) - log_assert (keyid_cmp (pk_main_keyid (pk), - pk_main_keyid (kb->pkt->pkt.public_key)) == 0); - - if (! pk && kb) - pk = kb->pkt->pkt.public_key; - if (!pk) - return '?'; /* Just in case a NULL PK is passed. */ - - trustlevel = get_validity (ctrl, kb, pk, uid, NULL, 0); - if ((trustlevel & TRUST_FLAG_REVOKED)) - return 'r'; - return trust_letter (trustlevel); -} - - -const char * -get_validity_string (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid) -{ - int trustlevel; - - if (!pk) - return "err"; /* Just in case a NULL PK is passed. */ - - trustlevel = get_validity (ctrl, NULL, pk, uid, NULL, 0); - if ((trustlevel & TRUST_FLAG_REVOKED)) - return _("revoked"); - return trust_value_to_string (trustlevel); -} +#include "key-clean.h" - /* * Mark the signature of the given UID which are used to certify it. * To do this, we first revmove all signatures which are not valid and diff --git a/g10/key-clean.h b/g10/key-clean.h new file mode 100644 index 0000000..4dfd950 --- /dev/null +++ b/g10/key-clean.h @@ -0,0 +1,37 @@ +/* key-clean.h - Functions to clean a keyblock + * 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 . + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef GNUPG_G10_KEY_CLEAN_H +#define GNUPG_G10_KEY_CLEAN_H + +#include "gpg.h" + +void mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, + u32 *main_kid, struct key_item *klist, + u32 curtime, u32 *next_expire); + +void clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, + int noisy, int self_only, + int *uids_cleaned, int *sigs_cleaned); +void clean_key (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, + int *uids_cleaned,int *sigs_cleaned); + + +#endif /*GNUPG_G10_KEY_CLEAN_H*/ diff --git a/g10/keydb.h b/g10/keydb.h index 70949e4..8e1a724 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -64,6 +64,20 @@ struct kbnode_struct { #define is_cloned_kbnode(a) ((a)->private_flag & 2) +/* + * A structure to store key identification as well as some stuff + * needed for key validation. + */ +struct key_item { + struct key_item *next; + unsigned int ownertrust,min_ownertrust; + byte trust_depth; + byte trust_value; + char *trust_regexp; + u32 kid[2]; +}; + + /* Bit flags used with build_pk_list. */ enum { @@ -133,6 +147,22 @@ enum }; +/* + * Check whether the signature SIG is in the klist K. + */ +static inline struct key_item * +is_in_klist (struct key_item *k, PKT_signature *sig) +{ + for (; k; k = k->next) + { + if (k->kid[0] == sig->keyid[0] && k->kid[1] == sig->keyid[1]) + return k; + } + return NULL; +} + + + /*-- keydb.c --*/ #define KEYDB_RESOURCE_FLAG_PRIMARY 2 /* The primary resource. */ diff --git a/g10/keyedit.c b/g10/keyedit.c index c3eca93..b717960 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -49,6 +49,7 @@ #include "../common/host2net.h" #include "tofu.h" #include "key-check.h" +#include "key-clean.h" #include "keyedit.h" static void show_prefs (PKT_user_id * uid, PKT_signature * selfsig, diff --git a/g10/trust.c b/g10/trust.c index 6d4f0e7..bd1c894 100644 --- a/g10/trust.c +++ b/g10/trust.c @@ -437,391 +437,3 @@ get_validity_string (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid) return _("revoked"); return trust_value_to_string (trustlevel); } - - - -/* - * Mark the signature of the given UID which are used to certify it. - * To do this, we first revmove all signatures which are not valid and - * from the remain ones we look for the latest one. If this is not a - * certification revocation signature we mark the signature by setting - * node flag bit 8. Revocations are marked with flag 11, and sigs - * from unavailable keys are marked with flag 12. Note that flag bits - * 9 and 10 are used for internal purposes. - */ -void -mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, - u32 *main_kid, struct key_item *klist, - u32 curtime, u32 *next_expire) -{ - kbnode_t node; - PKT_signature *sig; - - /* First check all signatures. */ - for (node=uidnode->next; node; node = node->next) - { - int rc; - - node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12); - if (node->pkt->pkttype == PKT_USER_ID - || node->pkt->pkttype == PKT_PUBLIC_SUBKEY - || node->pkt->pkttype == PKT_SECRET_SUBKEY) - break; /* ready */ - if (node->pkt->pkttype != PKT_SIGNATURE) - continue; - sig = node->pkt->pkt.signature; - if (main_kid - && sig->keyid[0] == main_kid[0] && sig->keyid[1] == main_kid[1]) - continue; /* ignore self-signatures if we pass in a main_kid */ - if (!IS_UID_SIG(sig) && !IS_UID_REV(sig)) - continue; /* we only look at these signature classes */ - if(sig->sig_class>=0x11 && sig->sig_class<=0x13 && - sig->sig_class-0x10flag |= 1<<12; - continue; - } - node->flag |= 1<<9; - } - /* Reset the remaining flags. */ - for (; node; node = node->next) - node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12); - - /* kbnode flag usage: bit 9 is here set for signatures to consider, - * bit 10 will be set by the loop to keep track of keyIDs already - * processed, bit 8 will be set for the usable signatures, and bit - * 11 will be set for usable revocations. */ - - /* For each cert figure out the latest valid one. */ - for (node=uidnode->next; node; node = node->next) - { - KBNODE n, signode; - u32 kid[2]; - u32 sigdate; - - if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY - || node->pkt->pkttype == PKT_SECRET_SUBKEY) - break; - if ( !(node->flag & (1<<9)) ) - continue; /* not a node to look at */ - if ( (node->flag & (1<<10)) ) - continue; /* signature with a keyID already processed */ - node->flag |= (1<<10); /* mark this node as processed */ - sig = node->pkt->pkt.signature; - signode = node; - sigdate = sig->timestamp; - kid[0] = sig->keyid[0]; kid[1] = sig->keyid[1]; - - /* Now find the latest and greatest signature */ - for (n=uidnode->next; n; n = n->next) - { - if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY - || n->pkt->pkttype == PKT_SECRET_SUBKEY) - break; - if ( !(n->flag & (1<<9)) ) - continue; - if ( (n->flag & (1<<10)) ) - continue; /* shortcut already processed signatures */ - sig = n->pkt->pkt.signature; - if (kid[0] != sig->keyid[0] || kid[1] != sig->keyid[1]) - continue; - n->flag |= (1<<10); /* mark this node as processed */ - - /* If signode is nonrevocable and unexpired and n isn't, - then take signode (skip). It doesn't matter which is - older: if signode was older then we don't want to take n - as signode is nonrevocable. If n was older then we're - automatically fine. */ - - if(((IS_UID_SIG(signode->pkt->pkt.signature) && - !signode->pkt->pkt.signature->flags.revocable && - (signode->pkt->pkt.signature->expiredate==0 || - signode->pkt->pkt.signature->expiredate>curtime))) && - (!(IS_UID_SIG(n->pkt->pkt.signature) && - !n->pkt->pkt.signature->flags.revocable && - (n->pkt->pkt.signature->expiredate==0 || - n->pkt->pkt.signature->expiredate>curtime)))) - continue; - - /* If n is nonrevocable and unexpired and signode isn't, - then take n. Again, it doesn't matter which is older: if - n was older then we don't want to take signode as n is - nonrevocable. If signode was older then we're - automatically fine. */ - - if((!(IS_UID_SIG(signode->pkt->pkt.signature) && - !signode->pkt->pkt.signature->flags.revocable && - (signode->pkt->pkt.signature->expiredate==0 || - signode->pkt->pkt.signature->expiredate>curtime))) && - ((IS_UID_SIG(n->pkt->pkt.signature) && - !n->pkt->pkt.signature->flags.revocable && - (n->pkt->pkt.signature->expiredate==0 || - n->pkt->pkt.signature->expiredate>curtime)))) - { - signode = n; - sigdate = sig->timestamp; - continue; - } - - /* At this point, if it's newer, it goes in as the only - remaining possibilities are signode and n are both either - revocable or expired or both nonrevocable and unexpired. - If the timestamps are equal take the later ordered - packet, presuming that the key packets are hopefully in - their original order. */ - - if (sig->timestamp >= sigdate) - { - signode = n; - sigdate = sig->timestamp; - } - } - - sig = signode->pkt->pkt.signature; - if (IS_UID_SIG (sig)) - { /* this seems to be a usable one which is not revoked. - * Just need to check whether there is an expiration time, - * We do the expired certification after finding a suitable - * certification, the assumption is that a signator does not - * want that after the expiration of his certificate the - * system falls back to an older certification which has a - * different expiration time */ - const byte *p; - u32 expire; - - p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL ); - expire = p? sig->timestamp + buf32_to_u32(p) : 0; - - if (expire==0 || expire > curtime ) - { - signode->flag |= (1<<8); /* yeah, found a good cert */ - if (next_expire && expire && expire < *next_expire) - *next_expire = expire; - } - } - else - signode->flag |= (1<<11); - } -} - - -static int -clean_sigs_from_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, - int noisy, int self_only) -{ - int deleted = 0; - kbnode_t node; - u32 keyid[2]; - - log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY - || keyblock->pkt->pkttype == PKT_SECRET_KEY); - - keyid_from_pk (keyblock->pkt->pkt.public_key, keyid); - - /* Passing in a 0 for current time here means that we'll never weed - out an expired sig. This is correct behavior since we want to - keep the most recent expired sig in a series. */ - mark_usable_uid_certs (ctrl, keyblock, uidnode, NULL, NULL, 0, NULL); - - /* What we want to do here is remove signatures that are not - considered as part of the trust calculations. Thus, all invalid - signatures are out, as are any signatures that aren't the last of - a series of uid sigs or revocations It breaks down like this: - coming out of mark_usable_uid_certs, if a sig is unflagged, it is - not even a candidate. If a sig has flag 9 or 10, that means it - was selected as a candidate and vetted. If a sig has flag 8 it - is a usable signature. If a sig has flag 11 it is a usable - revocation. If a sig has flag 12 it was issued by an unavailable - key. "Usable" here means the most recent valid - signature/revocation in a series from a particular signer. - - Delete everything that isn't a usable uid sig (which might be - expired), a usable revocation, or a sig from an unavailable - key. */ - - for (node=uidnode->next; - node && node->pkt->pkttype==PKT_SIGNATURE; - node=node->next) - { - int keep; - - keep = self_only? (node->pkt->pkt.signature->keyid[0] == keyid[0] - && node->pkt->pkt.signature->keyid[1] == keyid[1]) : 1; - - /* Keep usable uid sigs ... */ - if ((node->flag & (1<<8)) && keep) - continue; - - /* ... and usable revocations... */ - if ((node->flag & (1<<11)) && keep) - continue; - - /* ... and sigs from unavailable keys. */ - /* disabled for now since more people seem to want sigs from - unavailable keys removed altogether. */ - /* - if(node->flag & (1<<12)) - continue; - */ - - /* Everything else we delete */ - - /* At this point, if 12 is set, the signing key was unavailable. - If 9 or 10 is set, it's superseded. Otherwise, it's - invalid. */ - - if (noisy) - log_info ("removing signature from key %s on user ID \"%s\": %s\n", - keystr (node->pkt->pkt.signature->keyid), - uidnode->pkt->pkt.user_id->name, - node->flag&(1<<12)? "key unavailable": - node->flag&(1<<9)? "signature superseded" - /* */ :"invalid signature" ); - - delete_kbnode (node); - deleted++; - } - - return deleted; -} - - -/* This is substantially easier than clean_sigs_from_uid since we just - have to establish if the uid has a valid self-sig, is not revoked, - and is not expired. Note that this does not take into account - whether the uid has a trust path to it - just whether the keyholder - themselves has certified the uid. Returns true if the uid was - compacted. To "compact" a user ID, we simply remove ALL signatures - except the self-sig that caused the user ID to be remove-worthy. - We don't actually remove the user ID packet itself since it might - be resurrected in a later merge. Note that this function requires - that the caller has already done a merge_keys_and_selfsig(). - - TODO: change the import code to allow importing a uid with only a - revocation if the uid already exists on the keyring. */ - -static int -clean_uid_from_key (kbnode_t keyblock, kbnode_t uidnode, int noisy) -{ - kbnode_t node; - PKT_user_id *uid = uidnode->pkt->pkt.user_id; - int deleted = 0; - - log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY - || keyblock->pkt->pkttype == PKT_SECRET_KEY); - log_assert (uidnode->pkt->pkttype==PKT_USER_ID); - - /* Skip valid user IDs, compacted user IDs, and non-self-signed user - IDs if --allow-non-selfsigned-uid is set. */ - if (uid->created - || uid->flags.compacted - || (!uid->flags.expired && !uid->flags.revoked && opt.allow_non_selfsigned_uid)) - return 0; - - for (node=uidnode->next; - node && node->pkt->pkttype == PKT_SIGNATURE; - node=node->next) - { - if (!node->pkt->pkt.signature->flags.chosen_selfsig) - { - delete_kbnode (node); - deleted = 1; - uidnode->pkt->pkt.user_id->flags.compacted = 1; - } - } - - if (noisy) - { - const char *reason; - char *user = utf8_to_native (uid->name, uid->len, 0); - - if (uid->flags.revoked) - reason = _("revoked"); - else if (uid->flags.expired) - reason = _("expired"); - else - reason = _("invalid"); - - log_info ("compacting user ID \"%s\" on key %s: %s\n", - user, keystr_from_pk (keyblock->pkt->pkt.public_key), - reason); - - xfree (user); - } - - return deleted; -} - - -/* Needs to be called after a merge_keys_and_selfsig() */ -void -clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, - int noisy, int self_only, int *uids_cleaned, int *sigs_cleaned) -{ - int dummy = 0; - - log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY - || keyblock->pkt->pkttype == PKT_SECRET_KEY); - log_assert (uidnode->pkt->pkttype==PKT_USER_ID); - - if (!uids_cleaned) - uids_cleaned = &dummy; - - if (!sigs_cleaned) - sigs_cleaned = &dummy; - - /* Do clean_uid_from_key first since if it fires off, we don't have - to bother with the other. */ - *uids_cleaned += clean_uid_from_key (keyblock, uidnode, noisy); - if (!uidnode->pkt->pkt.user_id->flags.compacted) - *sigs_cleaned += clean_sigs_from_uid (ctrl, keyblock, uidnode, - noisy, self_only); -} - - -/* NB: This function marks the deleted nodes only and the caller is - * responsible to skip or remove them. */ -void -clean_key (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, - int *uids_cleaned, int *sigs_cleaned) -{ - kbnode_t node; - - merge_keys_and_selfsig (ctrl, keyblock); - - for (node = keyblock->next; - node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY - || node->pkt->pkttype == PKT_SECRET_SUBKEY); - node = node->next) - { - if (node->pkt->pkttype == PKT_USER_ID) - clean_one_uid (ctrl, keyblock, node, noisy, self_only, - uids_cleaned, sigs_cleaned); - } - - /* Remove bogus subkey binding signatures: The only signatures - * allowed are of class 0x18 and 0x28. */ - log_assert (!node || (node->pkt->pkttype == PKT_PUBLIC_SUBKEY - || node->pkt->pkttype == PKT_SECRET_SUBKEY)); - for (; node; node = node->next) - { - if (is_deleted_kbnode (node)) - continue; - if (node->pkt->pkttype == PKT_SIGNATURE - && !(IS_SUBKEY_SIG (node->pkt->pkt.signature) - || IS_SUBKEY_REV (node->pkt->pkt.signature))) - { - delete_kbnode (node); - if (sigs_cleaned) - ++*sigs_cleaned; - } - } -} diff --git a/g10/trustdb.c b/g10/trustdb.c index 2c2d239..8ef6db5 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -41,6 +41,7 @@ #include "tdbio.h" #include "trustdb.h" #include "tofu.h" +#include "key-clean.h" typedef struct key_item **KeyHashTable; /* see new_key_hash_table() */ diff --git a/g10/trustdb.h b/g10/trustdb.h index 4bc4ca9..d52fc53 100644 --- a/g10/trustdb.h +++ b/g10/trustdb.h @@ -46,36 +46,6 @@ #define NAMEHASH_LEN 20 -/* - * A structure to store key identification as well as some stuff needed - * for validation - */ -struct key_item { - struct key_item *next; - unsigned int ownertrust,min_ownertrust; - byte trust_depth; - byte trust_value; - char *trust_regexp; - u32 kid[2]; -}; - - -/* - * Check whether the signature SIG is in the klist K. - */ -static inline struct key_item * -is_in_klist (struct key_item *k, PKT_signature *sig) -{ - for (; k; k = k->next) - { - if (k->kid[0] == sig->keyid[0] && k->kid[1] == sig->keyid[1]) - return k; - } - return NULL; -} - - - /*-- trust.c --*/ int cache_disabled_value (ctrl_t ctrl, PKT_public_key *pk); void register_trusted_keyid (u32 *keyid); @@ -103,17 +73,6 @@ int get_validity_info (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk, const char *get_validity_string (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid); -void mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, - u32 *main_kid, struct key_item *klist, - u32 curtime, u32 *next_expire); - -void clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode, - int noisy, int self_only, - int *uids_cleaned, int *sigs_cleaned); -void clean_key (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only, - int *uids_cleaned,int *sigs_cleaned); - - /*-- trustdb.c --*/ void tdb_register_trusted_keyid (u32 *keyid); ----------------------------------------------------------------------- Summary of changes: g10/Makefile.am | 1 + g10/export.c | 19 +- g10/import.c | 31 ++- g10/{trust.c => key-clean.c} | 544 ++++++++++--------------------------------- g10/key-clean.h | 52 +++++ g10/keydb.h | 30 +++ g10/keyedit.c | 1 + g10/trust.c | 388 ------------------------------ g10/trustdb.c | 1 + g10/trustdb.h | 41 ---- 10 files changed, 249 insertions(+), 859 deletions(-) copy g10/{trust.c => key-clean.c} (58%) create mode 100644 g10/key-clean.h hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 9 10:58:08 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Mon, 09 Jul 2018 10:58:08 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-83-g7bc5d3c Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 7bc5d3c7e41c6e42a583a61a4c9504058fbb2976 (commit) from cacca62d06c6cf4a291f7ab2571cf52d671d140f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 7bc5d3c7e41c6e42a583a61a4c9504058fbb2976 Author: Andre Heinecke Date: Tue Jul 3 17:50:23 2018 +0200 Add ctx flag for auto-key-locate * src/context.h (gpgme_context): Add auto_key_locate. * src/engine-gpg.c (engine_gpg): Add auto_key_locate. (gpg_set_engine_flags, build_argv): Handle auto_key_locate. (gpg_release): Free auto_key_locate. * src/gpgme.c (gpgme_release): Free auto_key_locate. (gpgme_get_ctx_flag, gpgme_set_ctx_flag): Handle auto-key-locate. * doc/gpgme.texi: Document auto-key-locate flag. * tests/run-keylist.c (show_usage, main): Add --from-wkd option. -- This enables users of GPGME to control more fine grained what auto-key-locate does. Especially for WKD lookups / refreshes can this be useful. GnuPG-Bug-Id: T2917 Differential Revision: https://dev.gnupg.org/D463 diff --git a/NEWS b/NEWS index 9c64110..ae80642 100644 --- a/NEWS +++ b/NEWS @@ -4,12 +4,16 @@ Noteworthy changes in version 1.11.2 (unreleased) * Even for old versions of gpg a missing MDC will now lead to a decryption failure. + * Added context flag "auto-key-locate" to control the + behavior of GPGME_KEYLIST_MODE_LOCATE. + * Interface changes relative to the 1.11.1 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ gpgme_decrypt_result_t EXTENDED: New field legacy_cipher_nomdc. gpgme_set_ctx_flag EXTENDED: New flag 'ignore-mdc-error'. GPGME_AUDITLOG_DEFAULT NEW. GPGME_AUDITLOG_DIAG NEW. + gpgme_set_ctx_flag EXTENDED: New flag 'auto-key-locate'. cpp: DecryptionResult::sessionKey NEW. cpp: DecryptionResult::symkeyAlgo NEW. cpp: DecryptionResult::isLegacyCipherNoMDC New. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 3dac60d..6e328e6 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -3096,6 +3096,16 @@ result of the former try had the decryption result flag @code{legacy_cipher_nomdc} set. For failsafe reasons this flag is reset after each operation. + at item "auto-key-locate" +The string given in @var{value} is passed to gpg. This can be used +to change the behavior of a @code{GPGME_KEYLIST_MODE_LOCATE} keylisting. +Valid values are documented in the GnuPG manual and the gpg man page under +the option @option{--auto-key-locate}. +Requires at least GnuPG 2.1.18. + +Note: Keys retrieved through @code{auto-key-locate} are automatically +imported in the keyring. + @end table This function returns @code{0} on success. diff --git a/src/context.h b/src/context.h index bdab687..1c9379b 100644 --- a/src/context.h +++ b/src/context.h @@ -155,6 +155,9 @@ struct gpgme_context /* The optional request origin. */ char *request_origin; + /* The optional auto key locate options. */ + char *auto_key_locate; + /* The locale for the pinentry. */ char *lc_ctype; char *lc_messages; diff --git a/src/engine-gpg.c b/src/engine-gpg.c index f096bcb..be78957 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -140,6 +140,7 @@ struct engine_gpg struct gpgme_io_cbs io_cbs; gpgme_pinentry_mode_t pinentry_mode; char request_origin[10]; + char *auto_key_locate; struct { unsigned int no_symkey_cache : 1; @@ -453,6 +454,7 @@ gpg_release (void *engine) free_argv (gpg->argv); if (gpg->cmd.keyword) free (gpg->cmd.keyword); + free (gpg->auto_key_locate); gpgme_data_release (gpg->override_session_key); gpgme_data_release (gpg->diagnostics); @@ -659,6 +661,14 @@ gpg_set_engine_flags (void *engine, const gpgme_ctx_t ctx) else *gpg->request_origin = 0; + if (ctx->auto_key_locate && have_gpg_version (gpg, "2.1.18")) + { + if (gpg->auto_key_locate) + free (gpg->auto_key_locate); + gpg->auto_key_locate = _gpgme_strconcat ("--auto-key-locate=", + ctx->auto_key_locate, NULL); + } + gpg->flags.no_symkey_cache = (ctx->no_symkey_cache && have_gpg_version (gpg, "2.2.7")); gpg->flags.offline = (ctx->offline && have_gpg_version (gpg, "2.1.23")); @@ -958,6 +968,19 @@ build_argv (engine_gpg_t gpg, const char *pgmname) argc++; } + if (gpg->auto_key_locate) + { + argv[argc] = strdup (gpg->auto_key_locate); + if (!argv[argc]) + { + int saved_err = gpg_error_from_syserror (); + free (fd_data_map); + free_argv (argv); + return saved_err; + } + argc++; + } + if (gpg->flags.no_symkey_cache) { argv[argc] = strdup ("--no-symkey-cache"); diff --git a/src/gpgme.c b/src/gpgme.c index b03c7b8..2d829d9 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -249,6 +249,7 @@ gpgme_release (gpgme_ctx_t ctx) free (ctx->lc_messages); free (ctx->override_session_key); free (ctx->request_origin); + free (ctx->auto_key_locate); _gpgme_engine_info_release (ctx->engine_info); ctx->engine_info = NULL; DESTROY_LOCK (ctx->lock); @@ -546,6 +547,13 @@ gpgme_set_ctx_flag (gpgme_ctx_t ctx, const char *name, const char *value) { ctx->ignore_mdc_error = abool; } + else if (!strcmp (name, "auto-key-locate")) + { + free (ctx->auto_key_locate); + ctx->auto_key_locate = strdup (value); + if (!ctx->auto_key_locate) + err = gpg_error_from_syserror (); + } else err = gpg_error (GPG_ERR_UNKNOWN_NAME); @@ -599,6 +607,10 @@ gpgme_get_ctx_flag (gpgme_ctx_t ctx, const char *name) { return ctx->ignore_mdc_error? "1":""; } + else if (!strcmp (name, "auto-key-locate")) + { + return ctx->auto_key_locate? ctx->auto_key_locate : ""; + } else return NULL; } diff --git a/tests/run-keylist.c b/tests/run-keylist.c index 295251a..9725fa3 100644 --- a/tests/run-keylist.c +++ b/tests/run-keylist.c @@ -57,6 +57,7 @@ show_usage (int ex) " --import import all keys\n" " --offline use offline mode\n" " --from-file list all keys in the given file\n" + " --from-wkd list key from a web key directory\n" " --require-gnupg required at least the given GnuPG version\n" , stderr); exit (ex); @@ -100,6 +101,7 @@ main (int argc, char **argv) int only_secret = 0; int offline = 0; int from_file = 0; + int from_wkd = 0; gpgme_data_t data = NULL; @@ -194,6 +196,12 @@ main (int argc, char **argv) gpgme_set_global_flag ("require-gnupg", *argv); argc--; argv++; } + else if (!strcmp (*argv, "--from-wkd")) + { + argc--; argv++; + mode |= GPGME_KEYLIST_MODE_LOCATE; + from_wkd = 1; + } else if (!strncmp (*argv, "--", 2)) show_usage (1); } @@ -213,6 +221,13 @@ main (int argc, char **argv) gpgme_set_offline (ctx, offline); + if (from_wkd) + { + err = gpgme_set_ctx_flag (ctx, "auto-key-locate", + "clear,nodefault,wkd"); + fail_if_err (err); + } + if (from_file) { err = gpgme_data_new_from_file (&data, *argv, 1); ----------------------------------------------------------------------- Summary of changes: NEWS | 4 ++++ doc/gpgme.texi | 10 ++++++++++ src/context.h | 3 +++ src/engine-gpg.c | 23 +++++++++++++++++++++++ src/gpgme.c | 12 ++++++++++++ tests/run-keylist.c | 15 +++++++++++++++ 6 files changed, 67 insertions(+) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 9 11:30:06 2018 From: cvs at cvs.gnupg.org (by Maximilian Krambach) Date: Mon, 09 Jul 2018 11:30:06 +0200 Subject: [git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-70-g67b6fa5 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, javascript-binding has been updated via 67b6fa5a2948deed6a914c638f923fb9ad2eac66 (commit) from 10f2106404f01e7bb369fc66a597875fb455cd27 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 67b6fa5a2948deed6a914c638f923fb9ad2eac66 Author: Maximilian Krambach Date: Mon Jul 9 11:24:46 2018 +0200 js: reduce request spam at getKeys() -- * Don't make a secret-Key request for each Key retrieved, use one request for all of them instead, and assemble the info later. This should reduce the traffic with large Keyrings. The bulk retrieval for the public armored Keys for each of these Keys is still up to discussion * unittests: disabled assertion for the armored key (as it currently doesn't work) * encryptTest: clarified the mechanism/reason of rejection for Messages >64 MB. This is still a TODO, as this error comes from a different place (the browser itself) and behaves different from the other errors. diff --git a/lang/js/BrowserTestExtension/tests/encryptTest.js b/lang/js/BrowserTestExtension/tests/encryptTest.js index 2cb4e58..1114125 100644 --- a/lang/js/BrowserTestExtension/tests/encryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptTest.js @@ -133,7 +133,7 @@ describe('Encryption', function () { }); }).timeout(5000); - it('Overly large message ( > 65MB) is rejected', function (done) { + it('Overly large message ( > 64MB) is rejected', function (done) { let prm = Gpgmejs.init(); prm.then(function (context) { context.encrypt( @@ -142,10 +142,11 @@ describe('Encryption', function () { expect(answer).to.be.undefined; }, function(error){ expect(error).to.be.an.instanceof(Error); - // expect(error.code).to.equal('GNUPG_ERROR'); // TODO: there is a 64 MB hard limit at least in chrome at: // chromium//extensions/renderer/messaging_util.cc: // kMaxMessageLength + // The error will be a browser error, not from gnupg or from + // this library done(); }); }); diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index 358757b..09c43f7 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -56,28 +56,46 @@ export class GPGME_Keyring { } msg.post().then(function(result){ let resultset = []; - let promises = []; if (result.keys.length === 0){ resolve([]); } else { - for (let i=0; i< result.keys.length; i++){ - let k = createKey(result.keys[i].fingerprint); - k.setKeyData(result.keys[i]); - if (prepare_sync === true){ - promises.push(k.getArmor()); - promises.push(k.getHasSecret()); - } - resultset.push(k); - } - if (promises.length > 0) { - Promise.all(promises).then(function() { - resolve(resultset); - }, function(error){ - reject(error); - }); + let secondrequest; + if (prepare_sync === true) { + secondrequest = function() { + msg.setParameter('secret', true); + return msg.post(); + }; } else { - resolve(resultset); + secondrequest = function() { + return Promise.resolve(true); + }; } + secondrequest().then(function(answer) { + for (let i=0; i < result.keys.length; i++){ + if (prepare_sync === true){ + result.keys[i].hasSecret = false; + if (answer && answer.keys) { + for (let j=0; j < answer.keys.length; j++ ){ + if (result.keys[i].fingerprint === + answer.keys[j].fingerprint + ) { + if (answer.keys[j].secret === true){ + result.keys[i].hasSecret = true; + } + break; + } + } + // TODO getArmor() to be used in sync + } + } + let k = createKey(result.keys[i].fingerprint); + k.setKeyData(result.keys[i]); + resultset.push(k); + } + resolve(resultset); + }, function(error){ + reject(error); + }); } }); }); diff --git a/lang/js/unittests.js b/lang/js/unittests.js index 169e8eb..04e15ef 100644 --- a/lang/js/unittests.js +++ b/lang/js/unittests.js @@ -272,9 +272,9 @@ function unittests (){ keyring.getKeys(null, true).then(function(result){ expect(result).to.be.an('array'); expect(result[0]).to.be.an.instanceof(GPGME_Key); - expect(result[0].get('armored')).to.be.a('string'); - expect(result[0].get('armored')).to.include( - '-----END PGP PUBLIC KEY BLOCK-----'); + expect(result[0].get('hasSecret')).to.be.a('boolean'); + // expect(result[0].get('armored')).to.include( + // '-----END PGP PUBLIC KEY BLOCK-----'); done(); }); } @@ -287,9 +287,11 @@ function unittests (){ function(result){ expect(result).to.be.an('array'); expect(result[0]).to.be.an.instanceof(GPGME_Key); - expect(result[0].get('armored')).to.be.a('string'); - expect(result[0].get('armored')).to.include( - '-----END PGP PUBLIC KEY BLOCK-----'); + expect(result[0].get('hasSecret')).to.be.a('boolean'); + // TODO: preparing sync for armored is still in discussion + // expect(result[0].get('armored')).to.be.a('string'); + // expect(result[0].get('armored')).to.include( + // '-----END PGP PUBLIC KEY BLOCK-----'); done(); } ); ----------------------------------------------------------------------- Summary of changes: lang/js/BrowserTestExtension/tests/encryptTest.js | 5 ++- lang/js/src/Keyring.js | 52 +++++++++++++++-------- lang/js/unittests.js | 14 +++--- 3 files changed, 46 insertions(+), 25 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 9 11:39:39 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Mon, 09 Jul 2018 11:39:39 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-86-g40471ec Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 40471ec12f7b4ba37922813a02ebb2aaaa963b51 (commit) via c287f09ac0f090a65299ac7c15e3c9b4947d4b67 (commit) via 31bc51e2aff0a28b551410c9def2f578d0d28cea (commit) from 7bc5d3c7e41c6e42a583a61a4c9504058fbb2976 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 40471ec12f7b4ba37922813a02ebb2aaaa963b51 Author: Andre Heinecke Date: Mon Jul 9 11:36:28 2018 +0200 json: Add with-secret without secret only * src/gpgme-json.c (op_keylist, hlp_keylist): Add "with-secret" as a flag to do a public keylist with secret information. diff --git a/src/gpgme-json.c b/src/gpgme-json.c index 8d534c6..1604d2f 100644 --- a/src/gpgme-json.c +++ b/src/gpgme-json.c @@ -2117,7 +2117,8 @@ static const char hlp_keylist[] = "protocol: Either \"openpgp\" (default) or \"cms\".\n" "\n" "Optional boolean flags (default is false):\n" - "secret: List secret keys.\n" + "secret: List only secret keys.\n" + "with-secret: Add KEYLIST_MODE_WITH_SECRET.\n" "extern: Add KEYLIST_MODE_EXTERN.\n" "local: Add KEYLIST_MODE_LOCAL. (default mode).\n" "sigs: Add KEYLIST_MODE_SIGS.\n" @@ -2242,6 +2243,7 @@ op_keylist (cjson_t request, cjson_t result) gpgme_protocol_t protocol; char **patterns = NULL; int abool; + int secret_only = 0; gpgme_keylist_mode_t mode = 0; gpgme_key_t key = NULL; cjson_t keyarray = xjson_CreateArray (); @@ -2254,8 +2256,14 @@ op_keylist (cjson_t request, cjson_t result) if ((err = get_boolean_flag (request, "secret", 0, &abool))) goto leave; if (abool) + { + mode |= GPGME_KEYLIST_MODE_WITH_SECRET; + secret_only = 1; + } + if ((err = get_boolean_flag (request, "with-secret", 0, &abool))) + goto leave; + if (abool) mode |= GPGME_KEYLIST_MODE_WITH_SECRET; - if ((err = get_boolean_flag (request, "extern", 0, &abool))) goto leave; if (abool) @@ -2309,8 +2317,7 @@ op_keylist (cjson_t request, cjson_t result) gpgme_set_keylist_mode (ctx, mode); err = gpgme_op_keylist_ext_start (ctx, (const char **) patterns, - (mode & GPGME_KEYLIST_MODE_WITH_SECRET), - 0); + secret_only, 0); if (err) { gpg_error_object (result, err, "Error listing keys: %s", commit c287f09ac0f090a65299ac7c15e3c9b4947d4b67 Author: Andre Heinecke Date: Mon Jul 9 11:17:27 2018 +0200 tests: Add --with-secret to run-keylist.c * run-keylist.c (show_usage, main): Add --with-secret. diff --git a/tests/run-keylist.c b/tests/run-keylist.c index 9725fa3..9206b50 100644 --- a/tests/run-keylist.c +++ b/tests/run-keylist.c @@ -47,6 +47,7 @@ show_usage (int ex) " --openpgp use the OpenPGP protocol (default)\n" " --cms use the CMS protocol\n" " --secret list only secret keys\n" + " --with-secret list pubkeys with secret info filled\n" " --local use GPGME_KEYLIST_MODE_LOCAL\n" " --extern use GPGME_KEYLIST_MODE_EXTERN\n" " --sigs use GPGME_KEYLIST_MODE_SIGS\n" @@ -173,6 +174,11 @@ main (int argc, char **argv) mode |= GPGME_KEYLIST_MODE_VALIDATE; argc--; argv++; } + else if (!strcmp (*argv, "--with-secret")) + { + mode |= GPGME_KEYLIST_MODE_WITH_SECRET; + argc--; argv++; + } else if (!strcmp (*argv, "--import")) { import = 1; commit 31bc51e2aff0a28b551410c9def2f578d0d28cea Author: Andre Heinecke Date: Mon Jul 9 11:10:19 2018 +0200 doc: More explicit doc for EXTERN and LOCAL modes. * doc/gpgme.texi (GPGME_KEYLIST_MODE_EXTERN), (GPGME_KEYLIST_MODE_LOCATE, GPGME_KEYLIST_MODE_LOCAL): Mention command line flags for CMS and OpenPGP Protocol. -- This might help new users coming to gnupg to understand what the flags do. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 6e328e6..38d3480 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -2763,6 +2763,8 @@ The @code{GPGME_KEYLIST_MODE_LOCAL} symbol specifies that the local keyring should be searched for keys in the keylisting operation. This is the default. +Using only this option results in a @code{--list-keys}. + @item GPGME_KEYLIST_MODE_EXTERN The @code{GPGME_KEYLIST_MODE_EXTERN} symbol specifies that an external source should be searched for keys in the keylisting operation. The @@ -2770,10 +2772,14 @@ type of external source is dependent on the crypto engine used and whether it is combined with @code{GPGME_KEYLIST_MODE_LOCAL}. For example, it can be a remote keyserver or LDAP certificate server. +Using only this option results in a @code{--search-keys} for + at code{GPGME_PROTOCOL_OpenPGP} and something similar to + at code{--list-external-keys} for @code{GPGME_PROTOCOL_CMS}. + @item GPGME_KEYLIST_MODE_LOCATE This is a shortcut for the combination of - at code{GPGME_KEYLIST_MODE_LOCAL} and @code{GPGME_KEYLIST_MODE_EXTERN} -and convenient when the --locate-key feature of OpenPGP is desired. + at code{GPGME_KEYLIST_MODE_LOCAL} and @code{GPGME_KEYLIST_MODE_EXTERN}, which +results in a @code{--locate-keys} for @code{GPGME_PROTOCOL_OpenPGP}. @item GPGME_KEYLIST_MODE_SIGS The @code{GPGME_KEYLIST_MODE_SIGS} symbol specifies that the key ----------------------------------------------------------------------- Summary of changes: doc/gpgme.texi | 10 ++++++++-- src/gpgme-json.c | 15 +++++++++++---- tests/run-keylist.c | 6 ++++++ 3 files changed, 25 insertions(+), 6 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 9 11:57:30 2018 From: cvs at cvs.gnupg.org (by Maximilian Krambach) Date: Mon, 09 Jul 2018 11:57:30 +0200 Subject: [git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-71-g8964627 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, javascript-binding has been updated via 8964627f6ad7c407785a9fa5cb508c7c28be0d60 (commit) from 67b6fa5a2948deed6a914c638f923fb9ad2eac66 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 8964627f6ad7c407785a9fa5cb508c7c28be0d60 Author: Maximilian Krambach Date: Mon Jul 9 11:57:01 2018 +0200 js: fix verify result reporting -- * src/Signature.js: searching for overall validity in the "summary" property * BrowsertestExtension: Added two verify tests diff --git a/lang/js/BrowserTestExtension/browsertest.html b/lang/js/BrowserTestExtension/browsertest.html index f3d7a40..de8cd41 100644 --- a/lang/js/BrowserTestExtension/browsertest.html +++ b/lang/js/BrowserTestExtension/browsertest.html @@ -18,6 +18,7 @@ + diff --git a/lang/js/BrowserTestExtension/tests/verifyTest.js b/lang/js/BrowserTestExtension/tests/verifyTest.js new file mode 100644 index 0000000..bf0f0c0 --- /dev/null +++ b/lang/js/BrowserTestExtension/tests/verifyTest.js @@ -0,0 +1,86 @@ +/* gpgme.js - Javascript integration for gpgme + * Copyright (C) 2018 Bundesamt f?r Sicherheit in der Informationstechnik + * + * This file is part of GPGME. + * + * GPGME 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. + * + * GPGME 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 + * Lesser 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 . + * SPDX-License-Identifier: LGPL-2.1+ + * + * Author(s): + * Maximilian Krambach + */ + +/* global describe, it, expect, bigString, inputvalues, Gpgmejs */ + +let verifyData = { + signedMessage: '-----BEGIN PGP SIGNED MESSAGE-----\n' + + 'Hash: SHA256\n' + + '\n' + + 'Matschige M?nsteraner Marshmallows\n' + + '-----BEGIN PGP SIGNATURE-----\n' + + '\n' + + 'iQEzBAEBCAAdFiEE34YHmHCyv9oBiN3shwTx6WpaVdQFAlsqWxYACgkQhwTx6Wpa\n' + + 'VdRaTQf9Fj8agQzbE6DtonewZVGzj1KmjjpyAypnDldY21lrN8zIaQ+aKqRVkVrV\n' + + '5A/MeUfoHh0b/9G1Co4LOuNjGS14GRNlFvPtxeA2mCwlk7kgP2i6ekbHdEXWcG9c\n' + + 'gSbzdJ3EgfVCFNkC/yhldXSLOJZ7oyiGEteDpi8dDSa9dIprT++sQ4kRuR8jPrIi\n' + + 'UUY+DltG3it7PybcTFfQm53I0mtnpFsizzCmgyJAkfG5fwVL3uWwbYGofD049PSu\n' + + '6IEkSY74r8JbAbkCOiF/ln40RYGSwM0Ta5rrb3A3MixZNL/a1r17oljkaWz8e8VT\n' + + 'N7NUgBHwbIQ4e3RLuUU8fF3ICCGDOw==\n' + + '=oGai\n' + + '-----END PGP SIGNATURE-----\n' +}; + +describe('Verify data', function () { + it('Successful verify message', function (done) { + let message = verifyData.signedMessage; + let prm = Gpgmejs.init(); + prm.then(function (context) { + context.verify(message).then(function(result){ + expect(result.data).to.be.a('string'); + expect(result.all_valid).to.be.true; + expect(result.count).to.equal(1); + expect(result.signatures.good).to.be.an('array'); + expect(result.signatures.good.length).to.equal(1); + expect(result.signatures.good[0].fingerprint) + .to.be.a('string'); + expect(result.signatures.good[0].valid).to.be.true; + done(); + }); + }); + }); + + it('Encrypt-Sign-Verify random message', function (done) { + let message = bigString(2000); + let fpr = inputvalues.encrypt.good.fingerprint; + let prm = Gpgmejs.init(); + prm.then(function (context) { + context.encrypt(message, fpr).then(function(message_enc){ + context.sign(message_enc.data, fpr).then(function(message_encsign){ + context.verify(message_encsign.data).then(function(result){ + expect(result.data).to.equal(message_enc.data); + expect(result.data).to.be.a('string'); + expect(result.all_valid).to.be.true; + expect(result.count).to.equal(1); + expect(result.signatures.good).to.be.an('array'); + expect(result.signatures.good.length).to.equal(1); + expect(result.signatures.good[0].fingerprint) + .to.equal(fpr); + expect(result.signatures.good[0].valid).to.be.true; + done(); + }); + }); + }); + }); + }); +}); \ No newline at end of file diff --git a/lang/js/src/Signature.js b/lang/js/src/Signature.js index a07fc4d..c3c511a 100644 --- a/lang/js/src/Signature.js +++ b/lang/js/src/Signature.js @@ -67,7 +67,6 @@ export function createSignature(sigObject){ } } } - console.log('sig created'); return new GPGME_Signature(sigObject); } @@ -114,7 +113,7 @@ class GPGME_Signature { * additional information */ get valid() { - if (this._rawSigObject.valid === true){ + if (this._rawSigObject.summary.valid === true){ return true; } else { return false; ----------------------------------------------------------------------- Summary of changes: lang/js/BrowserTestExtension/browsertest.html | 1 + lang/js/BrowserTestExtension/tests/verifyTest.js | 86 ++++++++++++++++++++++++ lang/js/src/Signature.js | 3 +- 3 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 lang/js/BrowserTestExtension/tests/verifyTest.js hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 9 12:15:10 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Mon, 09 Jul 2018 12:15:10 +0200 Subject: [git] GnuPG - branch, master, updated. gnupg-2.2.7-177-g76989d5 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 76989d5bd89ed11f5b3656dc4748fcfc939a46dc (commit) from c2fd65ec8498a08ee36ca52d99b6b014f6db8d93 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 76989d5bd89ed11f5b3656dc4748fcfc939a46dc Author: Werner Koch Date: Mon Jul 9 12:01:02 2018 +0200 gpg: Remove multiple subkey bindings during export-clean. * g10/key-clean.c (clean_one_subkey_dupsigs): New. (clean_all_subkeys): Call it. -- GnuPG-bug-id: 3804 Signed-off-by: Werner Koch diff --git a/g10/key-clean.c b/g10/key-clean.c index 097ca17..f66a0db 100644 --- a/g10/key-clean.c +++ b/g10/key-clean.c @@ -479,6 +479,67 @@ clean_one_subkey (ctrl_t ctrl, kbnode_t subkeynode, int noisy, int clean_level) } +/* Helper for clean_all_subkeys. Here duplicate signatures from a + * subkey are removed. This should in general not happen because + * import takes care of that. However, sometimes other tools are used + * to manage a keyring or key has been imported a long time ago. */ +static int +clean_one_subkey_dupsigs (ctrl_t ctrl, kbnode_t subkeynode) +{ + kbnode_t node; + PKT_public_key *pk = subkeynode->pkt->pkt.public_key; + int any_choosen = 0; + int count = 0; + + (void)ctrl; + + log_assert (subkeynode->pkt->pkttype == PKT_PUBLIC_SUBKEY + || subkeynode->pkt->pkttype == PKT_SECRET_SUBKEY); + + if (DBG_LOOKUP) + log_debug ("\tchecking subkey %08lX for dupsigs\n", + (ulong) keyid_from_pk (pk, NULL)); + + /* First check that the choosen flag has been set. Note that we + * only look at plain signatures so to keep all revocation + * signatures which may carry important information. */ + for (node = subkeynode->next; + node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY + || node->pkt->pkttype == PKT_SECRET_SUBKEY); + node = node->next) + { + if (!is_deleted_kbnode (node) + && node->pkt->pkttype == PKT_SIGNATURE + && IS_SUBKEY_SIG (node->pkt->pkt.signature) + && node->pkt->pkt.signature->flags.chosen_selfsig) + { + any_choosen = 1; + break; + } + } + + if (!any_choosen) + return 0; /* Ooops no choosen flag set - we can't decide. */ + + for (node = subkeynode->next; + node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY + || node->pkt->pkttype == PKT_SECRET_SUBKEY); + node = node->next) + { + if (!is_deleted_kbnode (node) + && node->pkt->pkttype == PKT_SIGNATURE + && IS_SUBKEY_SIG (node->pkt->pkt.signature) + && !node->pkt->pkt.signature->flags.chosen_selfsig) + { + delete_kbnode (node); + count++; + } + } + + return count; +} + + /* This function only marks the deleted nodes and the caller is * responsible to skip or remove them. Needs to be called after a * merge_keys_and_selfsig. CLEAN_LEVEL is one of the KEY_CLEAN_* @@ -488,6 +549,7 @@ clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, int clean_level, int *subkeys_cleaned, int *sigs_cleaned) { kbnode_t first_subkey, node; + int n; if (DBG_LOOKUP) log_debug ("clean_all_subkeys: checking key %08lX\n", @@ -519,17 +581,34 @@ clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, int clean_level, /* Do the selected cleaning. */ if (clean_level > KEY_CLEAN_NONE) { + /* Clean enitre subkeys. */ for (node = first_subkey; node; node = node->next) { if (is_deleted_kbnode (node)) continue; if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) - if (clean_one_subkey (ctrl, node, noisy, clean_level)) - { - if (subkeys_cleaned) - ++*subkeys_cleaned; - } + { + if (clean_one_subkey (ctrl, node, noisy, clean_level)) + { + if (subkeys_cleaned) + ++*subkeys_cleaned; + } + } + } + + /* Clean duplicate signatures from a subkey. */ + for (node = first_subkey; node; node = node->next) + { + if (is_deleted_kbnode (node)) + continue; + if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY + || node->pkt->pkttype == PKT_SECRET_SUBKEY) + { + n = clean_one_subkey_dupsigs (ctrl, node); + if (sigs_cleaned) + *sigs_cleaned += n; + } } } } ----------------------------------------------------------------------- Summary of changes: g10/key-clean.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 5 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 9 12:17:03 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Mon, 09 Jul 2018 12:17:03 +0200 Subject: [git] GnuPG - branch, STABLE-BRANCH-2-2, updated. gnupg-2.2.8-28-g61562fe Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, STABLE-BRANCH-2-2 has been updated via 61562fe00027a4263f53661ad279072bd0b0133e (commit) from 8055f186a32e628028de897b7ee4705cd8e999b7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 61562fe00027a4263f53661ad279072bd0b0133e Author: Werner Koch Date: Mon Jul 9 12:01:02 2018 +0200 gpg: Remove multiple subkey bindings during export-clean. * g10/key-clean.c (clean_one_subkey_dupsigs): New. (clean_all_subkeys): Call it. -- GnuPG-bug-id: 3804 Signed-off-by: Werner Koch (cherry picked from commit 76989d5bd89ed11f5b3656dc4748fcfc939a46dc) diff --git a/g10/key-clean.c b/g10/key-clean.c index 097ca17..f66a0db 100644 --- a/g10/key-clean.c +++ b/g10/key-clean.c @@ -479,6 +479,67 @@ clean_one_subkey (ctrl_t ctrl, kbnode_t subkeynode, int noisy, int clean_level) } +/* Helper for clean_all_subkeys. Here duplicate signatures from a + * subkey are removed. This should in general not happen because + * import takes care of that. However, sometimes other tools are used + * to manage a keyring or key has been imported a long time ago. */ +static int +clean_one_subkey_dupsigs (ctrl_t ctrl, kbnode_t subkeynode) +{ + kbnode_t node; + PKT_public_key *pk = subkeynode->pkt->pkt.public_key; + int any_choosen = 0; + int count = 0; + + (void)ctrl; + + log_assert (subkeynode->pkt->pkttype == PKT_PUBLIC_SUBKEY + || subkeynode->pkt->pkttype == PKT_SECRET_SUBKEY); + + if (DBG_LOOKUP) + log_debug ("\tchecking subkey %08lX for dupsigs\n", + (ulong) keyid_from_pk (pk, NULL)); + + /* First check that the choosen flag has been set. Note that we + * only look at plain signatures so to keep all revocation + * signatures which may carry important information. */ + for (node = subkeynode->next; + node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY + || node->pkt->pkttype == PKT_SECRET_SUBKEY); + node = node->next) + { + if (!is_deleted_kbnode (node) + && node->pkt->pkttype == PKT_SIGNATURE + && IS_SUBKEY_SIG (node->pkt->pkt.signature) + && node->pkt->pkt.signature->flags.chosen_selfsig) + { + any_choosen = 1; + break; + } + } + + if (!any_choosen) + return 0; /* Ooops no choosen flag set - we can't decide. */ + + for (node = subkeynode->next; + node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY + || node->pkt->pkttype == PKT_SECRET_SUBKEY); + node = node->next) + { + if (!is_deleted_kbnode (node) + && node->pkt->pkttype == PKT_SIGNATURE + && IS_SUBKEY_SIG (node->pkt->pkt.signature) + && !node->pkt->pkt.signature->flags.chosen_selfsig) + { + delete_kbnode (node); + count++; + } + } + + return count; +} + + /* This function only marks the deleted nodes and the caller is * responsible to skip or remove them. Needs to be called after a * merge_keys_and_selfsig. CLEAN_LEVEL is one of the KEY_CLEAN_* @@ -488,6 +549,7 @@ clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, int clean_level, int *subkeys_cleaned, int *sigs_cleaned) { kbnode_t first_subkey, node; + int n; if (DBG_LOOKUP) log_debug ("clean_all_subkeys: checking key %08lX\n", @@ -519,17 +581,34 @@ clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, int clean_level, /* Do the selected cleaning. */ if (clean_level > KEY_CLEAN_NONE) { + /* Clean enitre subkeys. */ for (node = first_subkey; node; node = node->next) { if (is_deleted_kbnode (node)) continue; if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) - if (clean_one_subkey (ctrl, node, noisy, clean_level)) - { - if (subkeys_cleaned) - ++*subkeys_cleaned; - } + { + if (clean_one_subkey (ctrl, node, noisy, clean_level)) + { + if (subkeys_cleaned) + ++*subkeys_cleaned; + } + } + } + + /* Clean duplicate signatures from a subkey. */ + for (node = first_subkey; node; node = node->next) + { + if (is_deleted_kbnode (node)) + continue; + if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY + || node->pkt->pkttype == PKT_SECRET_SUBKEY) + { + n = clean_one_subkey_dupsigs (ctrl, node); + if (sigs_cleaned) + *sigs_cleaned += n; + } } } } ----------------------------------------------------------------------- Summary of changes: g10/key-clean.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 5 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 9 15:39:30 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Mon, 09 Jul 2018 15:39:30 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-39-gc30b7ee Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via c30b7ee64a1a84210301fe6619a586b4e8b507df (commit) via a81fe738434c3c28d6cda6c27f1d2a538c5277e8 (commit) via c60bc77de1bc8ab1dc6bad0a586b941ca678e63f (commit) from 1fbcd7cbfca750057fd8cb620257adb0a8f201ca (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit c30b7ee64a1a84210301fe6619a586b4e8b507df Author: Andre Heinecke Date: Mon Jul 9 15:37:28 2018 +0200 Fix crash for attachment names > 76 chars * src/rfc2047parse.c (rfc2047_decode_tokens): Use return value of realloc. -- This was introduced by me when porting rfc2047parse away from glib. *blushes* GnuPG-Bug-Id: T4062 diff --git a/src/rfc2047parse.c b/src/rfc2047parse.c index 5c96467..56e5dba 100644 --- a/src/rfc2047parse.c +++ b/src/rfc2047parse.c @@ -556,7 +556,7 @@ rfc2047_decode_tokens (rfc2047_token *tokens, size_t buflen) /* make sure our temporary output buffer is large enough... */ if (len > tmplen) { - xrealloc (outbuf, len + 1); + outbuf = xrealloc (outbuf, len + 1); tmplen = len + 1; } commit a81fe738434c3c28d6cda6c27f1d2a538c5277e8 Author: Andre Heinecke Date: Mon Jul 9 15:16:07 2018 +0200 tests: Don't override GNUPGHOME in run-parser * tests/run-parser.c (main): Don't override the GNUPGHOME -- This was useful back when I ran the parser test mostly on KMail's testcorpus but now when I use it to debug other errors it is better to let the user set the homedir. diff --git a/tests/run-parser.cpp b/tests/run-parser.cpp index 746742b..f759496 100644 --- a/tests/run-parser.cpp +++ b/tests/run-parser.cpp @@ -46,7 +46,6 @@ int main(int argc, char **argv) msgtype_t msgtype = MSGTYPE_UNKNOWN; FILE *fp_in = NULL; - putenv ((char*) "GNUPGHOME=" GPGHOMEDIR); gpgme_check_version (NULL); if (argc) commit c60bc77de1bc8ab1dc6bad0a586b941ca678e63f Author: Andre Heinecke Date: Mon Jul 9 15:09:13 2018 +0200 Fix linux build * src/parsecontroller.cpp (ParseController::parse): Ifdef native encoding workaround. diff --git a/src/parsecontroller.cpp b/src/parsecontroller.cpp index d61fc69..a984b6d 100644 --- a/src/parsecontroller.cpp +++ b/src/parsecontroller.cpp @@ -394,7 +394,7 @@ ParseController::parse() break; } } - +#ifdef HAVE_W32_SYSTEM if (allBad) { log_debug ("%s:%s:%p inline verify error trying native to utf8.", @@ -442,6 +442,7 @@ ParseController::parse() m_verify_result = ctx->verifyOpaqueSignature(input, output); } } +#endif } } delete ctx; ----------------------------------------------------------------------- Summary of changes: src/parsecontroller.cpp | 3 ++- src/rfc2047parse.c | 2 +- tests/run-parser.cpp | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 9 16:25:04 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Mon, 09 Jul 2018 16:25:04 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-42-gdb282a5 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via db282a59ab661e0060e244d55f7bc1d807f76102 (commit) via 2053f1a18e3c52c6a5ce78ff464924cf4278b54d (commit) via 5d5f49bb68289cc063f6c95124751ebe0800ad73 (commit) from c30b7ee64a1a84210301fe6619a586b4e8b507df (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit db282a59ab661e0060e244d55f7bc1d807f76102 Author: Andre Heinecke Date: Mon Jul 9 16:24:32 2018 +0200 Clarify logging for empty UID emails * src/mail.cpp (get_uid_for_sender): Check that email is not empty. diff --git a/src/mail.cpp b/src/mail.cpp index cb0c9e3..6850c69 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -1888,7 +1888,7 @@ get_uid_for_sender (const Key &k, const char *sender) for (const auto uid: k.userIDs()) { - if (!uid.email()) + if (!uid.email() || !*(uid.email())) { log_error ("%s:%s: skipping uid without email.", SRCNAME, __func__); commit 2053f1a18e3c52c6a5ce78ff464924cf4278b54d Author: Andre Heinecke Date: Mon Jul 9 16:22:34 2018 +0200 Implement "prefer-smime" option * src/cryptcontroller.cpp (CryptController::resolve_keys_cached): Respect prefer smime setting. -- Some prefer SM. GnuPG-Bug-Id: T3961 diff --git a/src/cryptcontroller.cpp b/src/cryptcontroller.cpp index dd36831..025a47d 100644 --- a/src/cryptcontroller.cpp +++ b/src/cryptcontroller.cpp @@ -316,15 +316,30 @@ CryptController::resolve_keys_cached() auto recps = cArray_to_vector ((const char**) m_recipient_addrs); recps.push_back (cached_sender); - m_recipients = cache->getEncryptionKeys(recps, GpgME::OpenPGP); - m_proto = GpgME::OpenPGP; + m_recipients.clear(); + if (opt.enable_smime && opt.prefer_smime) + { + m_recipients = cache->getEncryptionKeys(recps, GpgME::CMS); + if (!m_recipients.empty()) + { + fallbackToSMIME = true; + m_proto = GpgME::CMS; + } + } - if (m_recipients.empty() && opt.enable_smime) + if (m_recipients.empty()) + { + m_recipients = cache->getEncryptionKeys(recps, GpgME::OpenPGP); + m_proto = GpgME::OpenPGP; + } + + if (m_recipients.empty() && (opt.enable_smime && !opt.prefer_smime)) { m_recipients = cache->getEncryptionKeys(recps, GpgME::CMS); fallbackToSMIME = true; m_proto = GpgME::CMS; } + if (m_recipients.empty()) { log_debug ("%s:%s: Failed to resolve keys through cache", commit 5d5f49bb68289cc063f6c95124751ebe0800ad73 Author: Andre Heinecke Date: Mon Jul 9 16:19:35 2018 +0200 More options / config cleanup * src/main.cpp (write_options): Remove most options now controlled by the external dialog. (get_conf_bool): New helper. (read_options): Use it. * src/common_indep.c (set_default_key): Removed. * src/common_indep.h (opt): Remove obsolete values and add some new ones. -- Most of the removed options were already obsolete for ages. GnuPG-Bug-Id: T3944 diff --git a/src/common_indep.c b/src/common_indep.c index 7f4415f..046def8 100644 --- a/src/common_indep.c +++ b/src/common_indep.c @@ -749,22 +749,4 @@ log_window_hierarchy (HWND window, const char *fmt, ...) } } -void -set_default_key (const char *name) -{ - if (!lock_log ()) - { - if (!name || *name == '\"' || !*name) - { - xfree (opt.default_key); - opt.default_key = NULL; - } - else - { - xfree (opt.default_key); - opt.default_key = xstrdup (name);; - } - unlock_log (); - } -} #endif diff --git a/src/common_indep.h b/src/common_indep.h index 285ab42..00921e6 100644 --- a/src/common_indep.h +++ b/src/common_indep.h @@ -188,40 +188,19 @@ struct int enable_smime; /* Enable S/MIME support. */ int encrypt_default; /* Encrypt by default. */ int sign_default; /* Sign by default. */ - char *default_key; /* The key we want to always encrypt to. */ int prefer_html; /* Prefer html in html/text alternatives. */ int inline_pgp; /* Only for Addin. Use Inline PGP by default. */ int autoresolve; /* Autresolve keys with --locate-keys. */ int autosecure; /* Autmatically encrypt if locate returns enough validity. */ int reply_crypt; /* Only for Addin. Encrypt / Sign based on cryptostatus. */ + int automation; /* General automation */ + int autotrust; /* TOFU configured for GpgOL */ + int prefer_smime; /* S/MIME prefered when autoresolving */ int smime_html_warn_shown; /* Flag to save if unsigned smime warning was shown */ - /* The compatibility flags. */ - struct - { - unsigned int no_msgcache:1; - unsigned int no_pgpmime:1; - unsigned int no_oom_write:1; /* Don't write using Outlooks object model. */ - unsigned int no_preview_info:1; /* No preview info about PGP/MIME. */ - unsigned int old_reply_hack: 1; /* See gpgmsg.cpp:decrypt. */ - unsigned int auto_decrypt: 1; /* Try to decrypt when clicked. */ - unsigned int no_attestation: 1; /* Don't create an attestation. */ - unsigned int use_mwfmo: 1; /* Use MsgWaitForMultipleObjects. */ - } compat; - - /* The current git commit id. */ - unsigned int git_commit; - /* The forms revision number of the binary. */ int forms_revision; - /* The stored number of the binary which showed the last announcement. */ - int announce_number; - - /* Disable message processing until restart. This is required to - implement message reverting as a perparation to remove GpgOL. */ - int disable_gpgol; - } opt; diff --git a/src/main.c b/src/main.c index e0d553d..12754fb 100644 --- a/src/main.c +++ b/src/main.c @@ -212,6 +212,17 @@ drop_locale_dir (char *locale_dir) } +static int +get_conf_bool (const char *name, int defaultVal) +{ + char *val = NULL; + int ret; + load_extension_value (name, &val); + ret = val == NULL ? defaultVal : *val != '1' ? 0 : 1; + xfree (val); + return ret; +} + /* Read option settings from the Registry. */ void read_options (void) @@ -288,50 +299,26 @@ read_options (void) (opt.enable_debug & DBG_OOM_EXTRA)? " oom-extra":"" ); - - load_extension_value ("enableSmime", &val); - opt.enable_smime = !val ? 0 : atoi (val); - xfree (val); val = NULL; - - load_extension_value ("encryptDefault", &val); - opt.encrypt_default = val == NULL || *val != '1'? 0 : 1; - xfree (val); val = NULL; - - load_extension_value ("signDefault", &val); - opt.sign_default = val == NULL || *val != '1'? 0 : 1; - xfree (val); val = NULL; - - load_extension_value ("defaultKey", &val); - set_default_key (val); - xfree (val); val = NULL; - - load_extension_value ("gitCommit", &val); - opt.git_commit = val? strtoul (val, NULL, 16) : 0; - xfree (val); val = NULL; - - load_extension_value ("formsRevision", &val); - opt.forms_revision = val? atol (val) : 0; - xfree (val); val = NULL; - - load_extension_value ("announceNumber", &val); - opt.announce_number = val? atol (val) : 0; - xfree (val); val = NULL; - - load_extension_value ("inlinePGP", &val); - opt.inline_pgp = val == NULL || *val != '1'? 0 : 1; - xfree (val); val = NULL; - load_extension_value ("autoresolve", &val); - opt.autoresolve = val == NULL ? 1 : *val != '1' ? 0 : 1; - xfree (val); val = NULL; - load_extension_value ("replyCrypt", &val); - opt.reply_crypt = val == NULL ? 1 : *val != '1' ? 0 : 1; - xfree (val); val = NULL; - load_extension_value ("smimeHtmlWarnShown", &val); - opt.smime_html_warn_shown = val == NULL || *val != '1'? 0 : 1; - xfree (val); val = NULL; - load_extension_value ("autosecure", &val); - opt.autosecure = val == NULL ? 1 : *val != '1' ? 0 : 1; - xfree (val); val = NULL; + opt.enable_smime = get_conf_bool ("enableSmime", 0); + opt.encrypt_default = get_conf_bool ("encryptDefault", 0); + opt.sign_default = get_conf_bool ("signDefault", 0); + opt.inline_pgp = get_conf_bool ("inlinePGP", 0); + opt.reply_crypt = get_conf_bool ("replyCrypt", 1); + opt.prefer_smime = get_conf_bool ("preferSmime", 0); + opt.autoresolve = get_conf_bool ("autoresolve", 1); + opt.automation = get_conf_bool ("automation", 1); + opt.autosecure = get_conf_bool ("autosecure", 1); + opt.autotrust = get_conf_bool ("autotrust", 0); + opt.smime_html_warn_shown = get_conf_bool ("smimeHtmlWarnShown", 0); + + if (!opt.automation) + { + // Disabling automation is a shorthand to disable the + // others, too. + opt.autosecure = 0; + opt.autoresolve = 0; + opt.autotrust = 0; + } } @@ -346,16 +333,6 @@ write_options (void) int value; char *s_val; } table[] = { - {"enableSmime", 0, opt.enable_smime, NULL}, - {"encryptDefault", 0, opt.encrypt_default, NULL}, - {"signDefault", 0, opt.sign_default, NULL}, - {"logFile", 2, 0, (char*) get_log_file ()}, - {"gitCommit", 4, opt.git_commit, NULL}, - {"formsRevision", 1, opt.forms_revision, NULL}, - {"announceNumber", 1, opt.announce_number, NULL}, - {"inlinePGP", 0, opt.inline_pgp, NULL}, - {"autoresolve", 0, opt.autoresolve, NULL}, - {"replyCrypt", 0, opt.reply_crypt, NULL}, {"smimeHtmlWarnShown", 0, opt.smime_html_warn_shown, NULL}, {NULL, 0, 0, NULL} }; ----------------------------------------------------------------------- Summary of changes: src/common_indep.c | 18 ----------- src/common_indep.h | 27 ++-------------- src/cryptcontroller.cpp | 21 ++++++++++-- src/mail.cpp | 2 +- src/main.c | 85 ++++++++++++++++++------------------------------- 5 files changed, 53 insertions(+), 100 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 10 02:52:47 2018 From: cvs at cvs.gnupg.org (by Ben McGinnes) Date: Tue, 10 Jul 2018 02:52:47 +0200 Subject: [git] gnupg-doc - branch, master, updated. af6ff7f8443eb3353c77a6bdb2677eddbb0781fc Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GnuPG website and other docs". The branch, master has been updated via af6ff7f8443eb3353c77a6bdb2677eddbb0781fc (commit) from 08b7be30f76e65fdb742950eacffde2e09973ade (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit af6ff7f8443eb3353c77a6bdb2677eddbb0781fc Author: Ben McGinnes Date: Tue Jul 10 10:52:06 2018 +1000 donation page: * minor grammatical fix. diff --git a/web/donate/index.org b/web/donate/index.org index 3570a6e..b012451 100644 --- a/web/donate/index.org +++ b/web/donate/index.org @@ -24,7 +24,7 @@ *Many thanks to all supporters* If you are using [[../software/index.org][GnuPG]], [[../software/libgcrypt/index.org][Libgcrypt]], [[../software/gpgme/index.org][GPGME]], or [[https://www.gpg4win.org][Gpg4win]] and would like - to help with development and maintenance please consider to make a + to help with development and maintenance please consider making a donation. ** Ways to donate ----------------------------------------------------------------------- Summary of changes: web/donate/index.org | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- The GnuPG website and other docs http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 10 05:41:52 2018 From: cvs at cvs.gnupg.org (by Ben McGinnes) Date: Tue, 10 Jul 2018 05:41:52 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-88-g0e760e3 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 0e760e396fbf13e902d0dc0c048bff0d5410fa16 (commit) from 1eceacaff4ad5d6a4b759a7d00907dbc8278f12c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 0e760e396fbf13e902d0dc0c048bff0d5410fa16 Author: Ben McGinnes Date: Tue Jul 10 13:40:18 2018 +1000 example scripts: python work-arounds * fixed three typos which were guaranteed to break said script. diff --git a/lang/python/examples/howto/temp-homedir-config.py b/lang/python/examples/howto/temp-homedir-config.py index 3bb5cf3..1111fe2 100755 --- a/lang/python/examples/howto/temp-homedir-config.py +++ b/lang/python/examples/howto/temp-homedir-config.py @@ -91,17 +91,17 @@ else: userdir = os.path.expanduser("~") if new_homedir.startswith("~"): - new_homdir.replace("~", "") + new_homedir.replace("~", "") else: pass if new_homedir.startswith("/"): - new_homdir.replace("/", "") + new_homedir.replace("/", "") else: pass if new_homedir.startswith("."): - new_homdir.replace(".", "_") + new_homedir.replace(".", "_") else: pass ----------------------------------------------------------------------- Summary of changes: lang/python/examples/howto/temp-homedir-config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 10 10:14:16 2018 From: cvs at cvs.gnupg.org (by NIIBE Yutaka) Date: Tue, 10 Jul 2018 10:14:16 +0200 Subject: [git] GPG-ERROR - branch, master, updated. libgpg-error-1.31-9-g302d43a Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Error codes used by GnuPG et al.". The branch, master has been updated via 302d43a130e2364ea882474088a8b0a31bc325b9 (commit) from 1ac63f630cbe1b558ebe20b746bbe4962117d36f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 302d43a130e2364ea882474088a8b0a31bc325b9 Author: NIIBE Yutaka Date: Tue Jul 10 17:10:13 2018 +0900 build: Remove version_parts in autogen.sh. * autogen.rc (version_parts): Remove. * autogen.sh: Determine by $micro argument. -- It can be determined by the invocation of ./autogen.sh --find-version Signed-off-by: NIIBE Yutaka diff --git a/autogen.rc b/autogen.rc index 4e1918a..a15b3a3 100644 --- a/autogen.rc +++ b/autogen.rc @@ -3,8 +3,6 @@ display_name="Libgpg-error" patches_to="gnupg-devel at gnupg.org" -version_parts=2 - case "$myhost:$myhostsub" in w32:ce) extraoptions= diff --git a/autogen.sh b/autogen.sh index 23d27f3..9b36158 100755 --- a/autogen.sh +++ b/autogen.sh @@ -15,7 +15,7 @@ # configure it for the respective package. It is maintained as part of # GnuPG and source copied by other packages. # -# Version: 2018-02-21 +# Version: 2018-07-10 configure_ac="configure.ac" @@ -74,7 +74,6 @@ PRINT_HOST=no PRINT_BUILD=no tmp=$(dirname "$0") tsdir=$(cd "${tmp}"; pwd) -version_parts=3 if [ -n "${AUTOGEN_SH_SILENT}" ]; then SILENT=" --silent" @@ -239,18 +238,15 @@ if [ "$myhost" = "find-version" ]; then exit 1 fi - case "$version_parts" in - 2) - matchstr1="$package-$major.[0-9]*" - matchstr2="$package-$major-base" - vers="$major.$minor" - ;; - *) - matchstr1="$package-$major.$minor.[0-9]*" - matchstr2="$package-$major.$minor-base" - vers="$major.$minor.$micro" - ;; - esac + if [ -z "$micro" ]; then + matchstr1="$package-$major.[0-9]*" + matchstr2="$package-$major-base" + vers="$major.$minor" + else + matchstr1="$package-$major.$minor.[0-9]*" + matchstr2="$package-$major.$minor-base" + vers="$major.$minor.$micro" + fi beta=no if [ -e .git ]; then ----------------------------------------------------------------------- Summary of changes: autogen.rc | 2 -- autogen.sh | 24 ++++++++++-------------- 2 files changed, 10 insertions(+), 16 deletions(-) hooks/post-receive -- Error codes used by GnuPG et al. http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 10 10:31:34 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Tue, 10 Jul 2018 10:31:34 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-44-gc29f79c Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via c29f79c0d24c99227ba490cc0192ed97d6120d16 (commit) via d7bfab741b3aa7e0c734f4255c9d9f45c0f90fea (commit) from db282a59ab661e0060e244d55f7bc1d807f76102 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit c29f79c0d24c99227ba490cc0192ed97d6120d16 Author: Andre Heinecke Date: Tue Jul 10 10:30:51 2018 +0200 Use unique ptr for parser context * src/parsecontroller.cpp (ParseController::parse): Use unique ptr for GpgME Context. -- Wherever I see it I tend to change it. Makes the code easier. diff --git a/src/parsecontroller.cpp b/src/parsecontroller.cpp index a984b6d..29e5b30 100644 --- a/src/parsecontroller.cpp +++ b/src/parsecontroller.cpp @@ -282,7 +282,7 @@ ParseController::parse() { protocol = Protocol::OpenPGP; } - auto ctx = Context::createForProtocol (protocol); + auto ctx = std::unique_ptr (Context::createForProtocol (protocol)); if (!ctx) { log_error ("%s:%s:Failed to create context. Installation broken.", @@ -417,8 +417,7 @@ ParseController::parse() if (utf8) { // Try again after conversion. - delete ctx; - ctx = Context::createForProtocol (protocol); + ctx = std::unique_ptr (Context::createForProtocol (protocol)); ctx->setArmor (true); if (!m_sender.empty()) { @@ -445,7 +444,6 @@ ParseController::parse() #endif } } - delete ctx; log_debug ("%s:%s:%p: decrypt err: %i verify err: %i", SRCNAME, __func__, this, m_decrypt_result.error().code(), m_verify_result.error().code()); commit d7bfab741b3aa7e0c734f4255c9d9f45c0f90fea Author: Andre Heinecke Date: Tue Jul 10 10:27:50 2018 +0200 Use c++ linkage for oomhelp and conv w32getttext * src/mapihelp.h: Don't include oomhelp with c linkage. * src/oomhelp.h: Use C++ linkage. * src/Makefile.am: Update accordingly. * src/w32-gettext.c, src/w32-gettext.cpp: Renamed. Added casts for c++ and removed trailing whitespace. * src/w32-gettext.h: Use C linkage for gettext. -- We have some few C only files like common and main but mostly we are fully c++. Using C++ linkage will allow us to change oomhelp functions to work with C++ data types for better memory management. diff --git a/src/Makefile.am b/src/Makefile.am index 161bd88..500e286 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -67,7 +67,7 @@ gpgol_SOURCES = \ rfc2047parse.h rfc2047parse.c \ rfc822parse.c rfc822parse.h \ ribbon-callbacks.cpp ribbon-callbacks.h \ - w32-gettext.c w32-gettext.h \ + w32-gettext.cpp w32-gettext.h \ windowmessages.h windowmessages.cpp \ wks-helper.cpp wks-helper.h \ xmalloc.h diff --git a/src/mapihelp.h b/src/mapihelp.h index 43074f6..ede2cbf 100644 --- a/src/mapihelp.h +++ b/src/mapihelp.h @@ -20,18 +20,15 @@ #ifndef MAPIHELP_H #define MAPIHELP_H -#ifdef __cplusplus -extern "C" { -#if 0 -} -#endif -#endif #ifdef HAVE_CONFIG_H #include #endif #include +#ifdef __cplusplus +extern "C" { +#endif /* The filename of the attachment we create as the result of sign or encrypt operations. Don't change this name as some tests rely on it. */ diff --git a/src/oomhelp.h b/src/oomhelp.h index d4fd0f5..1136992 100644 --- a/src/oomhelp.h +++ b/src/oomhelp.h @@ -123,13 +123,6 @@ DEFINE_OLEGUID(IID_IOleWindow, 0x00000114, 0, 0); #define PR_BLOCK_STATUS_DASL \ "http://schemas.microsoft.com/mapi/proptag/0x10960003" -#ifdef __cplusplus -extern "C" { -#if 0 -} -#endif -#endif - /* Return the malloced name of an COM+ object. */ char *get_object_name (LPUNKNOWN obj); @@ -358,8 +351,5 @@ int get_ex_major_version_for_addr (const char *mbox); /* Get the language code used for Outlooks UI */ int get_ol_ui_language (void); -#ifdef __cplusplus char *get_sender_SendUsingAccount (LPDISPATCH mailitem, bool *r_is_GSuite); -} -#endif #endif /*OOMHELP_H*/ diff --git a/src/w32-gettext.c b/src/w32-gettext.cpp similarity index 98% rename from src/w32-gettext.c rename to src/w32-gettext.cpp index 081f050..0f67673 100644 --- a/src/w32-gettext.c +++ b/src/w32-gettext.cpp @@ -3,17 +3,17 @@ Copyright (C) 2005, 2007 g10 Code GmbH This file is part of libgpg-error. - + libgpg-error 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. - + libgpg-error 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 Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with libgpg-error; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA @@ -743,7 +743,7 @@ _nl_locale_name (int category, const char *categoryname) On some systems this can be done by the 'setlocale' function itself. */ # if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL retval = setlocale (category, NULL); -# else +# else /* Setting of LC_ALL overwrites all other. */ retval = getenv ("LC_ALL"); if (retval == NULL || retval[0] == '\0') @@ -1303,7 +1303,7 @@ free_domain (struct loaded_domain *domain) free (domain); } - + /* The gettext implementation; support functions. */ static struct loaded_domain * load_domain (const char *filename) @@ -1315,7 +1315,7 @@ load_domain (const char *filename) struct loaded_domain *domain = NULL; size_t to_read; char *read_ptr; - + fp = fopen (filename, "rb"); if (!fp) return NULL; @@ -1329,7 +1329,7 @@ load_domain (const char *filename) return NULL; } - data = malloc (size); + data = (mo_file_header*) malloc (size); if (!data) { fclose (fp); @@ -1362,7 +1362,7 @@ load_domain (const char *filename) return NULL; } - domain = calloc (1, sizeof *domain); + domain = (loaded_domain *) calloc (1, sizeof *domain); if (!domain) { free (data); @@ -1370,12 +1370,12 @@ load_domain (const char *filename) } domain->data = (char *) data; domain->must_swap = data->magic != MAGIC; - + /* Fill in the information about the available tables. */ switch (SWAPIT (domain->must_swap, data->revision)) { case 0: - + domain->nstrings = SWAPIT (domain->must_swap, data->nstrings); domain->orig_tab = (struct string_desc *) ((char *) data + SWAPIT (domain->must_swap, data->orig_tab_offset)); @@ -1394,7 +1394,7 @@ load_domain (const char *filename) } /* Allocate an array to keep track of code page mappings. */ - domain->mapped = calloc (1, domain->nstrings); + domain->mapped = (char *) calloc (1, domain->nstrings); if (!domain->mapped) { free (data); @@ -1421,7 +1421,7 @@ wchar_to_native (const wchar_t *string) if (n < 0) return NULL; - result = malloc (n+1); + result = (char*) malloc (n+1); if (!result) return NULL; @@ -1445,7 +1445,7 @@ native_to_wchar (const char *string) if (n < 0) return NULL; - result = malloc ((n+1) * sizeof *result); + result = (wchar_t *) malloc ((n+1) * sizeof *result); if (!result) return NULL; @@ -1474,7 +1474,7 @@ utf8_to_wchar (const char *string) if (n < 0) return NULL; - result = malloc ((n+1) * sizeof *result); + result = (wchar_t *) malloc ((n+1) * sizeof *result); if (!result) return NULL; @@ -1505,7 +1505,7 @@ wchar_to_utf8 (const wchar_t *string) if (n < 0) return NULL; - result = xmalloc (n+1); + result = (char *) xmalloc (n+1); n = WideCharToMultiByte (CP_UTF8, 0, string, -1, result, n, NULL, NULL); if (n < 0) { @@ -1544,7 +1544,7 @@ utf8_to_native (const char *string) char * native_to_utf8 (const char *string) { - char *result; + char *result; wchar_t *wstring; wstring = native_to_wchar (string); @@ -1568,7 +1568,7 @@ get_string (struct loaded_domain *domain, u32 idx, int utf8) char *p; p = domain->data + SWAPIT (domain->must_swap, domain->trans_tab[idx].offset); - if (!domain->mapped[idx]) + if (!domain->mapped[idx]) { size_t plen, buflen; char *buf; @@ -1586,7 +1586,7 @@ get_string (struct loaded_domain *domain, u32 idx, int utf8) in the overflow_space else and mark that in the mapped array. Because we expect that this won't happen too often, we use a simple linked list. */ - os = malloc (sizeof *os + buflen); + os = (overflow_space_s *) malloc (sizeof *os + buflen); if (os) { os->idx = idx; @@ -1596,17 +1596,17 @@ get_string (struct loaded_domain *domain, u32 idx, int utf8) p = os->d; } else - p = "ERROR in GETTEXT MALLOC"; + p = (char *) "ERROR in GETTEXT MALLOC"; } free (buf); } - else if (domain->mapped[idx] == 2) + else if (domain->mapped[idx] == 2) { /* We need to get the string from the overflow_space. */ for (os=domain->overflow_space; os; os = os->next) if (os->idx == idx) return (const char*) os->d; - p = "ERROR in GETTEXT\n"; + p = (char *) "ERROR in GETTEXT\n"; } return (const char*) p; } @@ -1645,7 +1645,7 @@ bindtextdomain (const char *domainname, const char *dirname) { char *p; - catval = malloc (strlen (catval_full) + 1); + catval = (char *)malloc (strlen (catval_full) + 1); if (catval) { strcpy (catval, catval_full); @@ -1664,7 +1664,7 @@ bindtextdomain (const char *domainname, const char *dirname) + strlen (domainname) + 3 + 1; char *p; - fname = malloc (len); + fname = (char*) malloc (len); if (!fname) { free (catval); diff --git a/src/w32-gettext.h b/src/w32-gettext.h index 9ef5525..cf72888 100644 --- a/src/w32-gettext.h +++ b/src/w32-gettext.h @@ -25,6 +25,13 @@ # define LC_MESSAGES 1729 #endif +#ifdef __cplusplus +extern "C" { +#if 0 +} +#endif +#endif + /* Specify that the DOMAINNAME message catalog will be found in DIRNAME rather than in the system locale data base. */ char *bindtextdomain (const char *domainname, const char *dirname); @@ -64,4 +71,6 @@ wchar_t *utf8_to_wchar (const char *string); char *utf8_to_native (const char *string); char *native_to_utf8 (const char *string); - +#ifdef __cplusplus +} +#endif ----------------------------------------------------------------------- Summary of changes: src/Makefile.am | 2 +- src/mapihelp.h | 9 +++---- src/oomhelp.h | 10 -------- src/parsecontroller.cpp | 6 ++--- src/{w32-gettext.c => w32-gettext.cpp} | 46 +++++++++++++++++----------------- src/w32-gettext.h | 11 +++++++- 6 files changed, 39 insertions(+), 45 deletions(-) rename src/{w32-gettext.c => w32-gettext.cpp} (98%) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 10 10:56:52 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Tue, 10 Jul 2018 10:56:52 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-45-g07c1895 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via 07c1895e78574c212e5d6c9db8cf6464bacb8ec2 (commit) from c29f79c0d24c99227ba490cc0192ed97d6120d16 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 07c1895e78574c212e5d6c9db8cf6464bacb8ec2 Author: Andre Heinecke Date: Tue Jul 10 10:50:33 2018 +0200 Improve recipient handling * src/cryptcontroller.cpp (CryptController::CryptController), src/keycache.cpp (KeyCache::isMailResolvable), src/wks-helper.cpp (WKSHelper::handle_confirmation_read): Update call to mail->getRecipients. * src/mail.h (Mail::getRecipients): Renamed to Mail::getCachedRecipients. * src/mail.cpp (Mail::getRecipients_o): Adapt to vector. Add error handling. (Mail::updateOOMData_o): Use vector directly. * src/oomhelp.cpp, src/oomhelp.h (get_oom_recipients): Use vector and provide an error. -- Downstream we already used the recipients mostly as a vector anyway to avoid the memory mangement hassle. This gives us more flexibility. Additionally we now report an error for the case from: GnuPG-Bug-Id: T4065 diff --git a/src/cryptcontroller.cpp b/src/cryptcontroller.cpp index 025a47d..9a9d4d6 100644 --- a/src/cryptcontroller.cpp +++ b/src/cryptcontroller.cpp @@ -70,7 +70,7 @@ CryptController::CryptController (Mail *mail, bool encrypt, bool sign, { log_debug ("%s:%s: CryptController ctor for %p encrypt %i sign %i inline %i.", SRCNAME, __func__, mail, encrypt, sign, mail->getDoPGPInline ()); - m_recipient_addrs = vector_to_cArray (mail->getRecipients ()); + m_recipient_addrs = vector_to_cArray (mail->getCachedRecipients ()); } CryptController::~CryptController() diff --git a/src/keycache.cpp b/src/keycache.cpp index 0e53c2d..72eea28 100644 --- a/src/keycache.cpp +++ b/src/keycache.cpp @@ -626,7 +626,7 @@ KeyCache::isMailResolvable(Mail *mail) { /* Get the data from the mail. */ const auto sender = mail->getSender (); - auto recps = mail->getRecipients (); + auto recps = mail->getCachedRecipients (); if (sender.empty() || recps.empty()) { diff --git a/src/mail.cpp b/src/mail.cpp index 6850c69..aaa15c5 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -1527,9 +1527,7 @@ Mail::updateOOMData_o () xfree (m_cached_plain_body); m_cached_plain_body = get_oom_string (m_mailitem, "Body"); - char **recipients = getRecipients_o (); - m_cached_recipients = cArray_to_vector ((const char **)recipients); - xfree (recipients); + m_cached_recipients = getRecipients_o (); } /* For some reason outlook may store the recipient address in the send using account field. If we have SMTP we prefer @@ -1779,17 +1777,34 @@ Mail::getHTMLBody_o () const return get_string_o (m_mailitem, "HTMLBody"); } -char ** +std::vector Mail::getRecipients_o () const { LPDISPATCH recipients = get_oom_object (m_mailitem, "Recipients"); if (!recipients) { TRACEPOINT; - return nullptr; + std::vector(); } - auto ret = get_oom_recipients (recipients); + bool err = false; + auto ret = get_oom_recipients (recipients, &err); gpgol_release (recipients); + + if (err) + { + /* Should not happen. But we add it for better bug reports. */ + const char *bugmsg = utf8_gettext ("Operation failed.\n\n" + "This is usually caused by a bug in GpgOL or an error in your setup.\n" + "Please see https://www.gpg4win.org/reporting-bugs.html " + "or ask your Administrator for support."); + char *buf; + gpgrt_asprintf (&buf, "Failed to resolve recipients.\n\n%s\n", bugmsg); + gpgol_message_box (get_active_hwnd (), + buf, + _("GpgOL"), MB_OK); + xfree(buf); + } + return ret; } @@ -2704,7 +2719,7 @@ Mail::locateKeys_o () updateOOMData_o (); KeyCache::instance()->startLocateSecret (getSender_o ().c_str (), this); KeyCache::instance()->startLocate (getSender_o ().c_str (), this); - KeyCache::instance()->startLocate (getRecipients (), this); + KeyCache::instance()->startLocate (getCachedRecipients (), this); autoresolveCheck (); locate_in_progress = false; @@ -2751,7 +2766,7 @@ Mail::getNeedsEncrypt () const } std::vector -Mail::getRecipients () +Mail::getCachedRecipients () { return m_cached_recipients; } diff --git a/src/mail.h b/src/mail.h index c6ecd2c..ef04c9f 100644 --- a/src/mail.h +++ b/src/mail.h @@ -394,10 +394,8 @@ public: /** Get the html of the mail */ std::string getHTMLBody_o () const; - /** Get the recipients recipients is a null - terminated array of strings. Needs to be freed - by the caller. */ - char ** getRecipients_o () const; + /** Get the recipients. */ + std::vector getRecipients_o () const; /** Try to locate the keys for all recipients */ void locateKeys_o (); @@ -421,7 +419,7 @@ public: char *takeCachedPlainBody (); /** Get the cached recipients. It is updated in update_oom_data.*/ - std::vector getRecipients (); + std::vector getCachedRecipients (); /** Returns 1 if the mail was encrypted, 2 if signed, 3 if both. Only valid after decrypt_verify. diff --git a/src/oomhelp.cpp b/src/oomhelp.cpp index 0826f49..8ed1842 100644 --- a/src/oomhelp.cpp +++ b/src/oomhelp.cpp @@ -1167,23 +1167,20 @@ get_recipient_addr_fallbacks (LPDISPATCH recipient) return nullptr; } -/* Gets a malloced NULL terminated array of recipent strings from - an OOM recipients Object. */ -char ** -get_oom_recipients (LPDISPATCH recipients) +/* Gets the resolved smtp addresses of the recpients. */ +std::vector +get_oom_recipients (LPDISPATCH recipients, bool *r_err) { int recipientsCnt = get_oom_int (recipients, "Count"); - char **recipientAddrs = NULL; + std::vector ret; int i; if (!recipientsCnt) { - return NULL; + return ret; } /* Get the recipients */ - recipientAddrs = (char**) xmalloc((recipientsCnt + 1) * sizeof(char*)); - recipientAddrs[recipientsCnt] = NULL; for (i = 1; i <= recipientsCnt; i++) { char buf[16]; @@ -1193,15 +1190,19 @@ get_oom_recipients (LPDISPATCH recipients) if (!recipient) { /* Should be impossible */ - recipientAddrs[i-1] = NULL; log_error ("%s:%s: could not find Item %i;", SRCNAME, __func__, i); + if (r_err) + { + *r_err = true; + } break; } char *resolved = get_pa_string (recipient, PR_SMTP_ADDRESS_DASL); if (resolved) { - recipientAddrs[i-1] = resolved; + ret.push_back (resolved); + xfree (resolved); gpgol_release (recipient); continue; } @@ -1209,7 +1210,8 @@ get_oom_recipients (LPDISPATCH recipients) resolved = get_recipient_addr_fallbacks (recipient); if (resolved) { - recipientAddrs[i-1] = resolved; + ret.push_back (resolved); + xfree (resolved); gpgol_release (recipient); continue; } @@ -1218,9 +1220,18 @@ get_oom_recipients (LPDISPATCH recipients) gpgol_release (recipient); log_debug ("%s:%s: Failed to look up Address probably EX addr is returned", SRCNAME, __func__); - recipientAddrs[i-1] = address; + if (address) + { + ret.push_back (address); + xfree (address); + } + else if (r_err) + { + *r_err = true; + } } - return recipientAddrs; + + return ret; } /* Add an attachment to the outlook dispatcher disp diff --git a/src/oomhelp.h b/src/oomhelp.h index 1136992..2fea2ce 100644 --- a/src/oomhelp.h +++ b/src/oomhelp.h @@ -25,6 +25,9 @@ #include #include "mymapi.h" +#include +#include + #define MSOCONTROLBUTTON 1 #define MSOCONTROLEDIT 2 #define MSOCONTROLDROPDOWN 3 @@ -172,8 +175,10 @@ void del_oom_button (LPDISPATCH button); /* Get the HWND of the active window in the current context */ HWND get_oom_context_window (LPDISPATCH context); -/* Get the address of the recipients as string list */ -char ** get_oom_recipients (LPDISPATCH recipients); +/* Get the address of the recipients as string list. + If r_err is not null it is set to true in case of an error. */ +std::vector get_oom_recipients (LPDISPATCH recipients, + bool *r_err = nullptr); /* Add an attachment to a dispatcher */ int diff --git a/src/wks-helper.cpp b/src/wks-helper.cpp index 7edb0ea..109ecab 100644 --- a/src/wks-helper.cpp +++ b/src/wks-helper.cpp @@ -797,21 +797,19 @@ WKSHelper::handle_confirmation_read (Mail *mail, LPSTREAM stream) const } /* Get the recipient of the confirmation mail */ - char **recipients = mail->getRecipients_o (); + const auto recipients = mail->getRecipients_o (); /* We assert that we have one recipient as the mail should have been sent by the wks-server. */ - if (!recipients || !recipients[0] || recipients[1]) + if (recipients.size() != 1) { log_error ("%s:%s: invalid recipients", SRCNAME, __func__); - release_cArray (recipients); gpgol_release (stream); return; } std::string mbox = recipients[0]; - release_cArray (recipients); /* Prepare stdin for the wks-client process */ ----------------------------------------------------------------------- Summary of changes: src/cryptcontroller.cpp | 2 +- src/keycache.cpp | 2 +- src/mail.cpp | 31 +++++++++++++++++++++++-------- src/mail.h | 8 +++----- src/oomhelp.cpp | 37 ++++++++++++++++++++++++------------- src/oomhelp.h | 9 +++++++-- src/wks-helper.cpp | 6 ++---- 7 files changed, 61 insertions(+), 34 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 10 12:29:19 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Tue, 10 Jul 2018 12:29:19 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-47-g7e6e15a Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via 7e6e15a8650ec232a1e07624b20bed9a4475fc50 (commit) via c49c5c8b511ef881159df7705b74ca02511f4c42 (commit) from 07c1895e78574c212e5d6c9db8cf6464bacb8ec2 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 7e6e15a8650ec232a1e07624b20bed9a4475fc50 Author: Andre Heinecke Date: Tue Jul 10 12:25:45 2018 +0200 Add support for distribution lists (groups) * src/oomhelp.cpp (get_recipient_addr_fallbacks): Handle distributionb lists and plit into (get_recipient_addr_entry_fallbacks_ex): New. Handle the exchange stuff. (try_resolve_group): Resolve distribution lists. (get_oom_recipients): Check for distribution lists. * src/oomhelp.h: Add some new defines. -- This adds support for contact groups / distribution lists. Not tested with exchange yet but it should work as the code for the exchange fallbacks is still used. GnuPG-Bug-Id: T4065 diff --git a/src/oomhelp.cpp b/src/oomhelp.cpp index 8ed1842..7884752 100644 --- a/src/oomhelp.cpp +++ b/src/oomhelp.cpp @@ -1105,23 +1105,10 @@ get_pa_int (LPDISPATCH pDisp, const char *property, int *rInt) return 0; } -/* Helper for additional fallbacks in recipient lookup */ +/* Helper for exchange address lookup. */ static char * -get_recipient_addr_fallbacks (LPDISPATCH recipient) +get_recipient_addr_entry_fallbacks_ex (LPDISPATCH addr_entry) { - if (!recipient) - { - return nullptr; - } - LPDISPATCH addr_entry = get_oom_object (recipient, "AddressEntry"); - - if (!addr_entry) - { - log_debug ("%s:%s: Failed to find AddressEntry", - SRCNAME, __func__); - return nullptr; - } - /* Maybe check for type here? We are pretty sure that we are exchange */ /* According to MSDN Message Boards the PR_EMS_AB_PROXY_ADDRESSES_DASL @@ -1137,7 +1124,6 @@ get_recipient_addr_fallbacks (LPDISPATCH recipient) { ret += 5; } - gpgol_release (addr_entry); return ret; } else @@ -1147,7 +1133,6 @@ get_recipient_addr_fallbacks (LPDISPATCH recipient) } LPDISPATCH ex_user = get_oom_object (addr_entry, "GetExchangeUser"); - gpgol_release (addr_entry); if (!ex_user) { log_debug ("%s:%s: Failed to find ExchangeUser", @@ -1163,10 +1148,153 @@ get_recipient_addr_fallbacks (LPDISPATCH recipient) SRCNAME, __func__, ret); return ret; } - return nullptr; } +/* Helper for additional fallbacks in recipient lookup */ +static char * +get_recipient_addr_fallbacks (LPDISPATCH recipient) +{ + if (!recipient) + { + return nullptr; + } + LPDISPATCH addr_entry = get_oom_object (recipient, "AddressEntry"); + + if (!addr_entry) + { + log_debug ("%s:%s: Failed to find AddressEntry", + SRCNAME, __func__); + return nullptr; + } + + char *ret = get_recipient_addr_entry_fallbacks_ex (addr_entry); + + gpgol_release (addr_entry); + + return ret; +} + +/* Try to resolve a recipient group and add it to the recipients vector. + + returns true on success. +*/ +static bool +try_resolve_group (LPDISPATCH addrEntry, std::vector &ret) +{ + /* Get the name for debugging */ + std::string name; + char *cname = get_oom_string (addrEntry, "Name"); + if (cname) + { + name = cname; + } + xfree (cname); + + int type = get_oom_int (addrEntry, "AddressEntryUserType"); + + if (type != DISTRIBUTION_LIST_ADDRESS_ENTRY_TYPE) + { + log_mime_parser ("%s:%s: type of %s is %i", + SRCNAME, __func__, name.c_str(), type); + return false; + } + + LPDISPATCH members = get_oom_object (addrEntry, "Members"); + addrEntry = nullptr; + + if (!members) + { + TRACEPOINT; + return false; + } + + int count = get_oom_int (members, "Count"); + + if (!count) + { + TRACEPOINT; + gpgol_release (members); + return false; + } + + bool foundOne = false; + for (int i = 1; i <= count; i++) + { + auto item_str = std::string("Item(") + std::to_string (i) + ")"; + LPDISPATCH entry = get_oom_object (members, item_str.c_str()); + if (!entry) + { + TRACEPOINT; + continue; + } + std::string entryName; + char *entry_name = get_oom_string (entry, "Name"); + if (entry_name) + { + entryName = entry_name; + xfree (entry_name); + } + + int subType = get_oom_int (entry, "AddressEntryUserType"); + /* Resolve recursively, yeah fun. */ + if (subType == DISTRIBUTION_LIST_ADDRESS_ENTRY_TYPE) + { + log_debug ("%s:%s: recursive address entry %s", + SRCNAME, __func__, + (opt.enable_debug & DBG_MIME_PARSER) ? + entryName.c_str() : "omitted"); + if (try_resolve_group (entry, ret)) + { + foundOne = true; + gpgol_release (entry); + continue; + } + } + + /* Resolve directly ? */ + char *addrtype = get_pa_string (entry, PR_ADDRTYPE_DASL); + if (addrtype && !strcmp (addrtype, "SMTP")) + { + xfree (addrtype); + char *resolved = get_pa_string (entry, PR_EMAIL_ADDRESS_DASL); + if (resolved) + { + ret.push_back(resolved); + foundOne = true; + gpgol_release (entry); + continue; + } + } + xfree (addrtype); + + /* Resolve through Exchange API */ + char *ex_resolved = get_recipient_addr_entry_fallbacks_ex (entry); + if (ex_resolved) + { + ret.push_back (ex_resolved); + foundOne = true; + gpgol_release (entry); + continue; + } + + gpgol_release (entry); + log_debug ("%s:%s: failed to resolve name %s", + SRCNAME, __func__, + (opt.enable_debug & DBG_MIME_PARSER) ? + entryName.c_str() : "omitted"); + } + gpgol_release (members); + if (!foundOne) + { + log_debug ("%s:%s: failed to resolve group %s", + SRCNAME, __func__, + (opt.enable_debug & DBG_MIME_PARSER) ? + name.c_str() : "omitted"); + } + return foundOne; +} + /* Gets the resolved smtp addresses of the recpients. */ std::vector get_oom_recipients (LPDISPATCH recipients, bool *r_err) @@ -1198,6 +1326,17 @@ get_oom_recipients (LPDISPATCH recipients, bool *r_err) } break; } + + LPDISPATCH addrEntry = get_oom_object (recipient, "AddressEntry"); + if (addrEntry && try_resolve_group (addrEntry, ret)) + { + log_debug ("%s:%s: Resolved recipient group", + SRCNAME, __func__); + gpgol_release (recipient); + gpgol_release (addrEntry); + continue; + } + char *resolved = get_pa_string (recipient, PR_SMTP_ADDRESS_DASL); if (resolved) { diff --git a/src/oomhelp.h b/src/oomhelp.h index 2fea2ce..4430b0c 100644 --- a/src/oomhelp.h +++ b/src/oomhelp.h @@ -99,6 +99,16 @@ DEFINE_OLEGUID(IID_IOleWindow, 0x00000114, 0, 0); "http://schemas.microsoft.com/mapi/proptag/0x7FFE000B" #endif +#ifndef PR_ADDRTYPE_DASL +#define PR_ADDRTYPE_DASL \ + "http://schemas.microsoft.com/mapi/proptag/0x3002001E" +#endif + +#ifndef PR_EMAIL_ADDRESS_DASL +#define PR_EMAIL_ADDRESS_DASL \ + "http://schemas.microsoft.com/mapi/proptag/0x3003001E" +#endif + #define PR_MESSAGE_CLASS_W_DASL \ "http://schemas.microsoft.com/mapi/proptag/0x001A001F" #define GPGOL_ATTACHTYPE_DASL \ @@ -126,6 +136,8 @@ DEFINE_OLEGUID(IID_IOleWindow, 0x00000114, 0, 0); #define PR_BLOCK_STATUS_DASL \ "http://schemas.microsoft.com/mapi/proptag/0x10960003" +#define DISTRIBUTION_LIST_ADDRESS_ENTRY_TYPE 11 + /* Return the malloced name of an COM+ object. */ char *get_object_name (LPUNKNOWN obj); commit c49c5c8b511ef881159df7705b74ca02511f4c42 Author: Andre Heinecke Date: Tue Jul 10 12:24:45 2018 +0200 Log keys used in internal resolution * src/cryptcontroller.cpp (CryptController::resolve_keys_cached): Log used keys. -- Can be helpful to detect problems. diff --git a/src/cryptcontroller.cpp b/src/cryptcontroller.cpp index 9a9d4d6..993c953 100644 --- a/src/cryptcontroller.cpp +++ b/src/cryptcontroller.cpp @@ -372,6 +372,18 @@ CryptController::resolve_keys_cached() return 1; } } + + log_debug ("%s:%s: Encrypting to:", + SRCNAME, __func__); + for (const auto &key: m_recipients) + { + log_debug ("%s", key.primaryFingerprint()); + } + if (!m_signer_key.isNull()) + { + log_debug ("%s:%s: Signing key: %s", + SRCNAME, __func__, m_signer_key.primaryFingerprint()); + } return 0; } ----------------------------------------------------------------------- Summary of changes: src/cryptcontroller.cpp | 12 ++++ src/oomhelp.cpp | 175 +++++++++++++++++++++++++++++++++++++++++++----- src/oomhelp.h | 12 ++++ 3 files changed, 181 insertions(+), 18 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 10 14:32:27 2018 From: cvs at cvs.gnupg.org (by Maximilian Krambach) Date: Tue, 10 Jul 2018 14:32:27 +0200 Subject: [git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-72-g4015f5b Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, javascript-binding has been updated via 4015f5b4983c8a4590aa71776880d8bc42c7918d (commit) from 8964627f6ad7c407785a9fa5cb508c7c28be0d60 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 4015f5b4983c8a4590aa71776880d8bc42c7918d Author: Maximilian Krambach Date: Tue Jul 10 14:32:26 2018 +0200 js: documentation -- * Fixed errors: - src/Message.js post(): Set chunksize to defined default value instead of hardcoded - src/Keys.js: added getHasSecret() to refreshKey operation. * Reviewed and updated the documentation * non-documentation changes which do not affect functionality: - src/Errors: disabled a console.warn that is only useful for debugging - helpers.js: renamed "string" to "value" in isFingerprint and isLongId to avoid confusion - src/Keyring: prepare_sync, search are both explicitly set to false by default diff --git a/lang/js/README b/lang/js/README index 86d2616..b7cd3d7 100644 --- a/lang/js/README +++ b/lang/js/README @@ -1,10 +1,17 @@ -gpgmejs, as contained in this directory, is a javascript library for direct use +gpgme.js, as contained in this directory, is a javascript library for direct use of gnupg in browsers, with the help of nativeMessaging. -Installation -------------- -gpgmejs uses webpack, and thus depends on nodejs for building. All dependencies -will be installed (in a local subdirectory) with the command `npm install`. +Prerequisites: +-------------- +gpgme.js will make use of the application gpgme-json, which is distributed with +gpgme. Gpgme-json needs to be installed; it will further need to accept the +browser extension in the manifest file. + +Building gpgme.js +----------------- +gpgme.js uses webpack, and thus depends on nodejs for building. All +dependencies will be installed (in a local subdirectory) with the command +`npm install`. To create a current version of the package, the command is `npx webpack --config webpack.conf.js`. @@ -14,7 +21,7 @@ in webpack.conf.js. Demo and Test WebExtension: --------------------------- -The Demo Extension shows simple examples of the usage of gpgmejs. +The Demo Extension shows simple examples of the usage of gpgme.js. The BrowsertestExtension runs more intensive tests (using the mocha and chai frameworks). Tests from BrowserTestExtension/tests will be run against the @@ -22,11 +29,11 @@ gpgmejs.bundle.js itself. They aim to test the outward facing functionality and API. Unittests as defined in ./unittests.js will be bundled in -gpgmejs_unittests.bundle.js, and test the separate components of gpgmejs, +gpgmejs_unittests.bundle.js, and test the separate components of gpgme.js, which mostly are not exported. -. The file `build_extension.sh` may serve as a pointer on how to -build and assemble these two Extensions and their dependencies. It can directly +The file `build_extension.sh` may serve as a pointer on how to build and +assemble these two Extensions and their dependencies. It can directly be used in most linux systems. The resulting folders can just be included in the extensions tab of the browser @@ -46,7 +53,7 @@ is needed, with the following content: ``` { "name": "gpgmejson", - "description": "This is a test application for gpgmejs", + "description": "This is a test application for gpgme.js", "path": "/usr/bin/gpgme-json", "type": "stdio", "allowed_origins": ["chrome-extension://ExtensionIdentifier/"] @@ -61,7 +68,7 @@ is needed, with the following content: ``` { "name": "gpgmejson", - "description": "This is a test application for gpgmejs", + "description": "This is a test application for gpgme.js", "path": "/usr/bin/gpgme-json", "type": "stdio", "allowed_extensions": ["ExtensionIdentifier at temporary-addon"] diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index 945932e..ef54dd6 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -28,7 +28,12 @@ import { gpgme_error } from './Errors'; import { GPGME_Message, createMessage } from './Message'; /** - * A Connection handles the nativeMessaging interaction. + * A Connection handles the nativeMessaging interaction via a port. As the + * protocol only allows up to 1MB of message sent from the nativeApp to the + * browser, the connection will stay open until all parts of a communication + * are finished. For a new request, a new port will open, to avoid mixing + * contexts. + * @class */ export class Connection{ @@ -37,19 +42,26 @@ export class Connection{ } /** - * Retrieves the information about the backend. - * @param {Boolean} details (optional) If set to false, the promise will - * just return a connection status - * @returns {Promise} result - * @returns {String} result.gpgme Version number of gpgme - * @returns {Array} result.info Further information about the - * backends. - * Example: + * @typedef {Object} backEndDetails + * @property {String} gpgme Version number of gpgme + * @property {Array} info Further information about the backend + * and the used applications (Example: + * { * "protocol": "OpenPGP", * "fname": "/usr/bin/gpg", * "version": "2.2.6", * "req_version": "1.4.0", * "homedir": "default" + * } + */ + + /** + * Retrieves the information about the backend. + * @param {Boolean} details (optional) If set to false, the promise will + * just return if a connection was successful. + * @returns {Promise|Promise} Details from the + * backend + * @async */ checkConnection(details = true){ if (details === true) { @@ -74,7 +86,7 @@ export class Connection{ } /** - * Immediately closes the open port. + * Immediately closes an open port. */ disconnect() { if (this._connection){ @@ -93,10 +105,13 @@ export class Connection{ } /** - * Sends a message and resolves with the answer. + * Sends a {@link GPGME_Message} via tghe nativeMessaging port. It resolves + * with the completed answer after all parts have been received and + * reassembled, or rejects with an {@link GPGME_Error}. + * * @param {GPGME_Message} message - * @returns {Promise} the gnupg answer, or rejection with error - * information. + * @returns {Promise} The collected answer + * @async */ post(message){ if (!message || !(message instanceof GPGME_Message)){ @@ -170,16 +185,25 @@ export class Connection{ /** * A class for answer objects, checking and processing the return messages of * the nativeMessaging communication. - * @param {String} operation The operation, to look up validity of returning - * messages + * @protected */ class Answer{ + /** + * @param {GPGME_Message} message + */ constructor(message){ this.operation = message.operation; this.expect = message.expect; } + /** + * Adds incoming base64 encoded data to the existing response + * @param {*} msg base64 encoded data. + * @returns {Boolean} + * + * @private + */ collect(msg){ if (typeof(msg) !== 'object' || !msg.hasOwnProperty('response')) { return gpgme_error('CONN_UNEXPECTED_ANSWER'); @@ -195,6 +219,10 @@ class Answer{ } } + /** + * Returns the base64 encoded answer data with the content verified against + * {@link permittedOperations}. + */ get message(){ if (this._responseb64 === undefined){ return gpgme_error('CONN_UNEXPECTED_ANSWER'); diff --git a/lang/js/src/Errors.js b/lang/js/src/Errors.js index a8cd8b5..cb5c94c 100644 --- a/lang/js/src/Errors.js +++ b/lang/js/src/Errors.js @@ -21,6 +21,9 @@ * Maximilian Krambach */ +/** + * Listing of all possible error codes and messages of a {@link GPGME_Error}. + */ const err_list = { // Connection 'CONN_NO_CONNECT': { @@ -107,10 +110,11 @@ const err_list = { }; /** - * Checks the given error code and returns an error object with some - * information about meaning and origin + * Checks the given error code and returns an {@link GPGME_Error} error object + * with some information about meaning and origin * @param {*} code Error code. Should be in err_list or 'GNUPG_ERROR' * @param {*} info Error message passed through if code is 'GNUPG_ERROR' + * @returns {GPGME_Error} */ export function gpgme_error(code = 'GENERIC_ERROR', info){ if (err_list.hasOwnProperty(code)){ @@ -119,7 +123,7 @@ export function gpgme_error(code = 'GENERIC_ERROR', info){ } if (err_list[code].type === 'warning'){ // eslint-disable-next-line no-console - console.warn(code + ': ' + err_list[code].msg); + // console.warn(code + ': ' + err_list[code].msg); } return null; } else if (code === 'GNUPG_ERROR'){ @@ -130,6 +134,14 @@ export function gpgme_error(code = 'GENERIC_ERROR', info){ } } +/** + * An error class with additional info about the origin of the error, as string + * @property {String} code Short description of origin and type of the error + * @property {String} msg Additional info + * @class + * @protected + * @extends Error + */ class GPGME_Error extends Error{ constructor(code, msg=''){ if (code === 'GNUPG_ERROR' && typeof(msg) === 'string'){ diff --git a/lang/js/src/Helpers.js b/lang/js/src/Helpers.js index b01fbc3..0fd1499 100644 --- a/lang/js/src/Helpers.js +++ b/lang/js/src/Helpers.js @@ -26,11 +26,11 @@ import { GPGME_Key } from './Key'; /** * Tries to return an array of fingerprints, either from input fingerprints or - * from Key objects (openpgp Keys or GPGME_Keys are both expected) - * @param {Object |Array| String|Array} input - * @returns {Array} Array of fingerprints. + * from Key objects (openpgp Keys or GPGME_Keys are both accepted). + * + * @param {Object | Array | String | Array} input + * @returns {Array} Array of fingerprints, or an empty array */ - export function toKeyIdArray(input){ if (!input){ return []; @@ -44,6 +44,8 @@ export function toKeyIdArray(input){ if (isFingerprint(input[i]) === true){ result.push(input[i]); } else { + // MSG_NOT_A_FPR is just a console warning if warning enabled + // in src/Errors.js gpgme_error('MSG_NOT_A_FPR'); } } else if (typeof(input[i]) === 'object'){ @@ -71,9 +73,11 @@ export function toKeyIdArray(input){ } /** - * check if values are valid hexadecimal values of a specified length - * @param {*} key input value. + * Check if values are valid hexadecimal values of a specified length + * @param {String} key input value. * @param {int} len the expected length of the value + * @returns {Boolean} true if value passes test + * @private */ function hextest(key, len){ if (!key || typeof(key) !== 'string'){ @@ -87,15 +91,21 @@ function hextest(key, len){ } /** - * check if the input is a valid Hex string with a length of 40 + * check if the input is a valid Fingerprint + * (Hex string with a length of 40 characters) + * @param {String} value to check + * @returns {Boolean} true if value passes test */ -export function isFingerprint(string){ - return hextest(string, 40); +export function isFingerprint(value){ + return hextest(value, 40); } /** - * check if the input is a valid Hex string with a length of 16 + * check if the input is a valid gnupg long ID (Hex string with a length of 16 + * characters) + * @param {String} value to check + * @returns {Boolean} true if value passes test */ -export function isLongId(string){ - return hextest(string, 16); +export function isLongId(value){ + return hextest(value, 16); } diff --git a/lang/js/src/Key.js b/lang/js/src/Key.js index 88c2b92..30f507c 100644 --- a/lang/js/src/Key.js +++ b/lang/js/src/Key.js @@ -26,8 +26,9 @@ import { gpgme_error } from './Errors'; import { createMessage } from './Message'; /** - * Validates the fingerprint. + * Validates the given fingerprint and creates a new {@link GPGME_Key} * @param {String} fingerprint + * @returns {GPGME_Key|GPGME_Error} */ export function createKey(fingerprint){ if (!isFingerprint(fingerprint)){ @@ -37,12 +38,13 @@ export function createKey(fingerprint){ } /** - * Representing the Keys as stored in GPG + * Represents the Keys as stored in the gnupg backend * It allows to query almost all information defined in gpgme Key Objects - * Refer to validKeyProperties for available information, and the gpgme + * Refer to {@link validKeyProperties} for available information, and the gpgme * documentation on their meaning * (https://www.gnupg.org/documentation/manuals/gpgme/Key-objects.html) * + * @class */ export class GPGME_Key { @@ -62,6 +64,9 @@ export class GPGME_Key { } } + /** + * @returns {String} The fingerprint defining this Key + */ get fingerprint(){ if (!this._data || !this._data.fingerprint){ return gpgme_error('KEY_INVALID'); @@ -70,11 +75,11 @@ export class GPGME_Key { } /** - * - * @param {Object} data Bulk set data for this key, with the Object as sent + * @param {Object} data Bulk set the data for this key, with an Object sent * by gpgme-json. - * @returns {GPGME_Key|GPGME_Error} The Key object itself after values have - * been set + * @returns {GPGME_Key|GPGME_Error} Itself after values have been set, an + * error if something went wrong + * @private */ setKeyData(data){ if (this._data === undefined) { @@ -126,12 +131,17 @@ export class GPGME_Key { } /** - * Query any property of the Key list - * @param {String} property Key property to be retreived - * @param {*} cached (optional) if false, the data will be directly queried - * from gnupg. - * @returns {*|Promise<*>} the value, or if not cached, a Promise - * resolving on the value + * Query any property of the Key listed in {@link validKeyProperties} + * @param {String} property property to be retreived + * @param {Boolean} cached (optional) if false, the data will be directly + * queried from gnupg, and the operation will be asynchronous. Else, the + * data will be fetched from the state of the initialization of the Key. + * The cached mode may contain outdated information, but can be used as + * synchronous operation, where the backend is not expected to change Keys + * during a session. The key still can be reloaded by invoking + * {@link refreshKey}. + * @returns {*|Promise<*>} the value (Boolean, String, Array, Object). + * If 'cached' is true, the value will be resolved as a Promise. */ get(property, cached=true) { if (cached === false) { @@ -164,7 +174,12 @@ export class GPGME_Key { } /** - * Reloads the Key from gnupg + * Reloads the Key information from gnupg. This is only useful if you use + * the GPGME_Keys cached. Note that this is a performance hungry operation. + * If you desire more than a few refreshs, it may be advisable to run + * {@link Keyring.getKeys} instead. + * @returns {Promise} + * @async */ refreshKey() { let me = this; @@ -178,7 +193,12 @@ export class GPGME_Key { msg.post().then(function(result){ if (result.keys.length === 1){ me.setKeyData(result.keys[0]); - resolve(me); + me.getHasSecret().then(function(){ + //TODO retrieve armored Key + resolve(me); + }, function(error){ + reject(error); + }); } else { reject(gpgme_error('KEY_NOKEY')); } @@ -189,9 +209,9 @@ export class GPGME_Key { } /** - * Query the armored block of the non- secret parts of the Key directly - * from gpg. - * @returns {Promise} + * Query the armored block of the Key directly from gnupg. Please note that + * this will not get you any export of the secret/private parts of a Key + * @returns {Promise} * @async */ getArmor(){ @@ -213,9 +233,12 @@ export class GPGME_Key { } /** - * Find out if the Key includes a secret part - * @returns {Promise} - * + * Find out if the Key includes a secret part. Note that this is a rather + * nonperformant operation, as it needs to query gnupg twice. If you want + * this inforrmation about more than a few Keys, it may be advisable to run + * {@link Keyring.getKeys} instead. + * @returns {Promise} True if a secret/private Key is + * available in the gnupg Keyring * @async */ getHasSecret(){ @@ -253,25 +276,30 @@ export class GPGME_Key { */ /** - * @returns {String} The armored public Key block + * Property for the export of armored Key. If the armored Key is not + * cached, it returns an {@link GPGME_Error} with code 'KEY_NO_INIT'. + * Running {@link refreshKey} may help in this case. + * @returns {String|GPGME_Error} The armored public Key block. */ get armored(){ return this.get('armored', true); } /** - * @returns {Boolean} If the key is considered a "private Key", - * i.e. owns a secret subkey. + * Property indicating if the Key possesses a private/secret part. If this + * information is not yet cached, it returns an {@link GPGME_Error} with + * code 'KEY_NO_INIT'. Running {@link refreshKey} may help in this case. + * @returns {Boolean} If the Key has a secret subkey. */ get hasSecret(){ return this.get('hasSecret', true); } /** - * Deletes the public Key from the GPG Keyring. Note that a deletion of a + * Deletes the (public) Key from the GPG Keyring. Note that a deletion of a * secret key is not supported by the native backend. - * @returns {Promise} Success if key was deleted, rejects with a - * GPG error otherwise + * @returns {Promise} Success if key was deleted, + * rejects with a GPG error otherwise. */ delete(){ let me = this; @@ -291,10 +319,17 @@ export class GPGME_Key { } /** - * The subkeys of a Key. Currently, they cannot be refreshed separately + * Representing a subkey of a Key. + * @class + * @protected */ class GPGME_Subkey { + /** + * Initializes with the json data sent by gpgme-json + * @param {Object} data + * @private + */ constructor(data){ let keys = Object.keys(data); for (let i=0; i< keys.length; i++) { @@ -302,6 +337,13 @@ class GPGME_Subkey { } } + /** + * Validates a subkey property against {@link validSubKeyProperties} and + * sets it if validation is successful + * @param {String} property + * @param {*} value + * @param private + */ setProperty(property, value){ if (!this._data){ this._data = {}; @@ -318,10 +360,9 @@ class GPGME_Subkey { } /** - * + * Fetches any information about this subkey * @param {String} property Information to request - * @returns {String | Number} - * TODO: date properties are numbers with Date in seconds + * @returns {String | Number | Date} */ get(property) { if (this._data.hasOwnProperty(property)){ @@ -330,15 +371,31 @@ class GPGME_Subkey { } } +/** + * Representing user attributes associated with a Key or subkey + * @class + * @protected + */ class GPGME_UserId { + /** + * Initializes with the json data sent by gpgme-json + * @param {Object} data + * @private + */ constructor(data){ let keys = Object.keys(data); for (let i=0; i< keys.length; i++) { this.setProperty(keys[i], data[keys[i]]); } } - + /** + * Validates a subkey property against {@link validUserIdProperties} and + * sets it if validation is successful + * @param {String} property + * @param {*} value + * @param private + */ setProperty(property, value){ if (!this._data){ this._data = {}; @@ -356,10 +413,9 @@ class GPGME_UserId { } /** - * + * Fetches information about the user * @param {String} property Information to request * @returns {String | Number} - * TODO: date properties are numbers with Date in seconds */ get(property) { if (this._data.hasOwnProperty(property)){ @@ -368,6 +424,13 @@ class GPGME_UserId { } } +/** + * Validation definition for userIds. Each valid userId property is represented + * as a key- Value pair, with their value being a validation function to check + * against + * @protected + * @const + */ const validUserIdProperties = { 'revoked': function(value){ return typeof(value) === 'boolean'; @@ -419,6 +482,12 @@ const validUserIdProperties = { } }; +/** + * Validation definition for subKeys. Each valid userId property is represented + * as a key-value pair, with the value being a validation function + * @protected + * @const + */ const validSubKeyProperties = { 'invalid': function(value){ return typeof(value) === 'boolean'; @@ -471,8 +540,14 @@ const validSubKeyProperties = { return (Number.isInteger(value) && value > 0); } }; + +/** + * Validation definition for Keys. Each valid Key property is represented + * as a key-value pair, with their value being a validation function + * @protected + * @const + */ const validKeyProperties = { - //TODO better validation? 'fingerprint': function(value){ return isFingerprint(value); }, diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index 09c43f7..a0bdfcb 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -27,24 +27,30 @@ import {createKey} from './Key'; import { isFingerprint } from './Helpers'; import { gpgme_error } from './Errors'; +/** + * This class offers access to the gnupg keyring + */ export class GPGME_Keyring { constructor(){ } /** - * @param {String} pattern (optional) pattern A pattern to search for, - * in userIds or KeyIds - * @param {Boolean} prepare_sync (optional, default true) if set to true, - * Key.armor and Key.hasSecret will be called, so they can be used - * inmediately. This allows for full synchronous use. If set to false, - * these will initially only be available as Promises in getArmor() and - * getHasSecret() - * @param {Boolean} search (optional) retrieve the Keys from servers with - * the method(s) defined in gnupg (e.g. WKD/HKP lookup) - * @returns {Promise.>} + * Queries Keys (all Keys or a subset) from gnupg. * + * @param {String | Array} pattern (optional) A pattern to search + * for in userIds or KeyIds. + * @param {Boolean} prepare_sync (optional) if set to true, the 'hasSecret' + * and 'armored' properties will be fetched for the Keys as well. These + * require additional calls to gnupg, resulting in a performance hungry + * operation. Calling them here enables direct, synchronous use of these + * properties for all keys, without having to resort to a refresh() first. + * @param {Boolean} search (optional) retrieve Keys from external servers + * with the method(s) defined in gnupg (e.g. WKD/HKP lookup) + * @returns {Promise.|GPGME_Error>} + * @static + * @async */ - getKeys(pattern, prepare_sync, search){ + getKeys(pattern, prepare_sync=false, search=false){ return new Promise(function(resolve, reject) { let msg = createMessage('keylist'); if (pattern !== undefined){ @@ -102,10 +108,15 @@ export class GPGME_Keyring { } /** - * Fetches the armored public Key blocks for all Keys matchin the pattern - * (if no pattern is given, fetches all known to gnupg) - * @param {String|Array} pattern (optional) - * @returns {Promise} Armored Key blocks + * Fetches the armored public Key blocks for all Keys matching the pattern + * (if no pattern is given, fetches all keys known to gnupg). Note that the + * result may be one big armored block, instead of several smaller armored + * blocks + * @param {String|Array} pattern (optional) The Pattern to search + * for + * @returns {Promise} Armored Key blocks + * @static + * @async */ getKeysArmored(pattern) { return new Promise(function(resolve, reject) { @@ -123,15 +134,14 @@ export class GPGME_Keyring { } /** - * Returns the Key to be used by default for signing operations, - * looking up the gpg configuration, or returning the first key that - * contains a secret key. - * @returns {Promise} - * + * Returns the Key used by default in gnupg. + * (a.k.a. 'primary Key or 'main key'). + * It looks up the gpg configuration if set, or the first key that contains + * a secret key. * - * TODO: getHasSecret always returns false at this moment, so this fucntion - * still does not fully work as intended. - * * @async + * @returns {Promise} + * @async + * @static */ getDefaultKey() { let me = this; @@ -177,30 +187,40 @@ export class GPGME_Keyring { } /** + * @typedef {Object} importResult The result of a Key update + * @property {Object} summary Numerical summary of the result. See the + * feedbackValues variable for available Keys values and the gnupg + * documentation. + * https://www.gnupg.org/documentation/manuals/gpgme/Importing-Keys.html + * for details on their meaning. + * @property {Array} Keys Array of Object containing + * GPGME_Keys with additional import information * + */ + + /** + * @typedef {Object} importedKeyResult + * @property {GPGME_Key} key The resulting key + * @property {String} status: + * 'nochange' if the Key was not changed, + * 'newkey' if the Key was imported in gpg, and did not exist previously, + * 'change' if the key existed, but details were updated. For details, + * Key.changes is available. + * @property {Boolean} changes.userId Changes in userIds + * @property {Boolean} changes.signature Changes in signatures + * @property {Boolean} changes.subkey Changes in subkeys + */ + + /** + * Import an armored Key block into gnupg. Note that this currently will + * not succeed on private Key blocks. * @param {String} armored Armored Key block of the Key(s) to be imported * into gnupg * @param {Boolean} prepare_sync prepare the keys for synched use - * (see getKeys()). - * - * @returns {Promise} result: A summary and an array of Keys - * considered - * - * @returns result.summary: Numerical summary of the result. See the - * feedbackValues variable for available values and the gnupg documentation - * https://www.gnupg.org/documentation/manuals/gpgme/Importing-Keys.html - * for details on their meaning. - * @returns {Array} result.Keys: Array of objects containing: - * @returns {GPGME_Key} Key.key The resulting key - * @returns {String} Key.status: - * 'nochange' if the Key was not changed, - * 'newkey' if the Key was imported in gpg, and did not exist - * previously, - * 'change' if the key existed, but details were updated. For - * details, Key.changes is available. - * @returns {Boolean} Key.changes.userId: userIds changed - * @returns {Boolean} Key.changes.signature: signatures changed - * @returns {Boolean} Key.changes.subkey: subkeys changed + * (see {@link getKeys}). + * @returns {Promise} A summary and Keys considered. + * @async + * @static */ importKey(armored, prepare_sync) { let feedbackValues = ['considered', 'no_user_id', 'imported', @@ -283,25 +303,36 @@ export class GPGME_Keyring { } + /** + * Convenience function for deleting a Key. See {@link Key.delete} for + * further information about the return values. + * @param {String} fingerprint + * @returns {Promise} + * @async + * @static + */ deleteKey(fingerprint){ if (isFingerprint(fingerprint) === true) { let key = createKey(fingerprint); - key.delete(); + return key.delete(); + } else { + return Promise.reject(gpgme_error('KEY_INVALID')); } } /** * Generates a new Key pair directly in gpg, and returns a GPGME_Key * representing that Key. Please note that due to security concerns, secret - * Keys can not be _deleted_ from inside gpgmejs. + * Keys can not be deleted or exported from inside gpgme.js. * - * @param {String} userId The user Id, e.g. "Foo Bar " - * @param {*} algo (optional) algorithm (and optionally key size to be - * used. See {@link supportedKeyAlgos } below for supported values. + * @param {String} userId The user Id, e.g. 'Foo Bar ' + * @param {String} algo (optional) algorithm (and optionally key size) to + * be used. See {@link supportedKeyAlgos} below for supported values. * @param {Date} expires (optional) Expiration date. If not set, expiration * will be set to 'never' * - * @return {Promise} + * @return {Promise} + * @async */ generateKey(userId, algo = 'default', expires){ if ( @@ -336,7 +367,8 @@ export class GPGME_Keyring { } /** - * A list of algorithms supported for key generation. + * List of algorithms supported for key generation. Please refer to the gnupg + * documentation for details */ const supportedKeyAlgos = [ 'default', diff --git a/lang/js/src/Message.js b/lang/js/src/Message.js index 7ccf7ef..2e38142 100644 --- a/lang/js/src/Message.js +++ b/lang/js/src/Message.js @@ -25,6 +25,12 @@ import { permittedOperations } from './permittedOperations'; import { gpgme_error } from './Errors'; import { Connection } from './Connection'; +/** + * Initializes a message for gnupg, validating the message's purpose with + * {@link permittedOperations} first + * @param {String} operation + * @returns {GPGME_Message|GPGME_Error} The Message object + */ export function createMessage(operation){ if (typeof(operation) !== 'string'){ return gpgme_error('PARAM_WRONG'); @@ -37,12 +43,13 @@ export function createMessage(operation){ } /** - * Prepares a communication request. It checks operations and parameters in - * ./permittedOperations. - * @param {String} operation + * A Message collects, validates and handles all information required to + * successfully establish a meaningful communication with gpgme-json via + * {@link Connection.post}. The definition on which communication is available + * can be found in {@link permittedOperations}. + * @class */ export class GPGME_Message { - //TODO getter constructor(operation){ this.operation = operation; @@ -63,9 +70,13 @@ export class GPGME_Message { } /** - * Set the maximum size of responses from gpgme in bytes. Values allowed - * range from 10kB to 1MB. The lower limit is arbitrary, the upper limit - * fixed by browsers' nativeMessaging specifications + * The maximum size of responses from gpgme in bytes. As of July 2018, + * most browsers will only accept answers up to 1 MB of size. Everything + * above that threshold will not pass through nativeMessaging; answers that + * are larger need to be sent in parts. The lower limit is set to 10 KB. + * Messages smaller than the threshold will not encounter problems, larger + * messages will be received in chunks. + * If the value is not explicitly specified, 1023 KB is used. */ set chunksize(value){ if ( @@ -85,8 +96,9 @@ export class GPGME_Message { } /** - * If expect is set to 'base64', the response is expected to be base64 - * encoded binary + * Expect indicates which format data is expected to be in. It currently + * only supports 'base64', indicating that the response data from gnupg are + * expected to be base64 encoded binary */ set expect(value){ if (value ==='base64'){ @@ -103,13 +115,13 @@ export class GPGME_Message { /** - * Sets a parameter for the message. Note that the operation has to be set - * first, to be able to check if the parameter is permittted + * Sets a parameter for the message. It validates with + * {@link permittedOperations} * @param {String} param Parameter to set - * @param {any} value Value to set //TODO: Some type checking + * @param {any} value Value to set * @returns {Boolean} If the parameter was set successfully */ - setParameter(param,value){ + setParameter( param,value ){ if (!param || typeof(param) !== 'string'){ return gpgme_error('PARAM_WRONG'); } @@ -125,6 +137,7 @@ export class GPGME_Message { } else { return gpgme_error('PARAM_WRONG'); } + // check incoming value for correctness let checktype = function(val){ switch(typeof(val)){ case 'string': @@ -187,9 +200,9 @@ export class GPGME_Message { } /** - * Check if the message has the minimum requirements to be sent, according - * to the definitions in permittedOperations - * @returns {Boolean} + * Check if the message has the minimum requirements to be sent, that is + * all 'required' parameters according to {@link permittedOperations}. + * @returns {Boolean} true if message is complete. */ get isComplete(){ if (!this._msg.op){ @@ -222,13 +235,18 @@ export class GPGME_Message { } + /** + * Sends the Message via nativeMessaging and resolves with the answer. + * @returns {Promise} + * @async + */ post(){ let me = this; return new Promise(function(resolve, reject) { if (me.isComplete === true) { let conn = new Connection; if (me._msg.chunksize === undefined){ - me._msg.chunksize = 1023*1024; + me._msg.chunksize = me.chunksize; } conn.post(me).then(function(response) { resolve(response); diff --git a/lang/js/src/Signature.js b/lang/js/src/Signature.js index c3c511a..191e00a 100644 --- a/lang/js/src/Signature.js +++ b/lang/js/src/Signature.js @@ -20,17 +20,16 @@ * Author(s): * Maximilian Krambach */ +import { gpgme_error } from './Errors'; /** - * Validates a signature object and returns + * Validates an object containing a signature, as sent by the nativeMessaging + * interface * @param {Object} sigObject Object as returned by gpgme-json. The definition - * of the expected values are to be found in the constants 'expKeys', 'expSum', - * 'expNote' in this file. - * @returns {GPGME_Signature} Signature Object + * of the expected values are to be found in {@link expKeys}, {@link expSum}, + * {@link expNote}. + * @returns {GPGME_Signature|GPGME_Error} Signature Object */ - -import { gpgme_error } from './Errors'; - export function createSignature(sigObject){ if ( typeof(sigObject) !=='object' || @@ -72,18 +71,20 @@ export function createSignature(sigObject){ /** - * Representing the details of a signature. It is supposed to be read-only. The - * full details as given by gpgme-json can be accessed from the _rawSigObject. - * ) + * Representing the details of a signature. The full details as given by + * gpgme-json can be read from the _rawSigObject. + * + * Note to reviewers: This class should be read only except via + * {@link createSignature} + * @protected + * @class */ class GPGME_Signature { + constructor(sigObject){ this._rawSigObject = sigObject; } - /** - * The signatures' fingerprint - */ get fingerprint(){ return this._rawSigObject.fingerprint; } @@ -105,7 +106,7 @@ class GPGME_Signature { * @returns {Date} */ get timestamp(){ - return new Date(this._rawSigObject.timestamp* 1000); + return new Date(this._rawSigObject.timestamp * 1000); } /** diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index f49361d..3f6dc94 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -28,10 +28,62 @@ import { gpgme_error } from './Errors'; import { GPGME_Keyring } from './Keyring'; import { createSignature } from './Signature'; +/** + * @typedef {Object} decrypt_result + * @property {String} data The decrypted data + * @property {Boolean} base64 indicating whether data is base64 encoded. + * @property {Boolean} is_mime (optional) the data claims to be a MIME + * object. + * @property {String} file_name (optional) the original file name + * @property {signatureDetails} signatures Verification details for + * signatures + */ + +/** + * @typedef {Object} signatureDetails + * @property {Boolean} all_valid Summary if all signatures are fully valid + * @property {Number} count Number of signatures found + * @property {Number} failures Number of invalid signatures + * @property {Array} signatures.good All valid signatures + * @property {Array} signatures.bad All invalid signatures + */ + +/** + * @typedef {Object} encrypt_result The result of an encrypt operation + * @property {String} data The encrypted message + * @property {Boolean} base64 Indicating whether data is base64 encoded. + */ + +/** + * @typedef { GPGME_Key | String | Object } inputKeys + * Accepts different identifiers of a gnupg Key that can be parsed by + * {@link toKeyIdArray}. Expected inputs are: One or an array of + * GPGME_Keys; one or an array of fingerprint strings; one or an array of + * openpgpjs Key objects. + */ + +/** + * @typedef {Object} signResult The result of a signing operation + * @property {String} data The resulting data. Includes the signature in + * clearsign mode + * @property {String} signature The detached signature (if in detached mode) + */ + +/** @typedef {Object} verifyResult The result of a verification + * @property {Boolean} data: The verified data + * @property {Boolean} is_mime (optional) the data claims to be a MIME + * object. + * @property {String} file_name (optional) the original file name + * @property {signatureDetails} signatures Verification details for + * signatures + */ + +/** + * The main entry point for gpgme.js. + * @class + */ export class GpgME { - /** - * initializes GpgME by opening a nativeMessaging port - */ + constructor(){ } @@ -41,6 +93,9 @@ export class GpgME { } } + /** + * Accesses the {@link GPGME_Keyring}. + */ get Keyring(){ if (!this._Keyring){ this._Keyring = new GPGME_Keyring; @@ -49,23 +104,23 @@ export class GpgME { } /** - * Encrypt (and optionally sign) a Message + * Encrypt (and optionally sign) data * @param {String|Object} data text/data to be encrypted as String. Also * accepts Objects with a getText method - * @param {GPGME_Key|String|Array|Array} publicKeys + * @param {inputKeys} publicKeys * Keys used to encrypt the message - * @param {GPGME_Key|String|Array|Array} secretKeys - * (optional) Keys used to sign the message + * @param {inputKeys} secretKeys (optional) Keys used to sign the message. + * If Keys are present, the operation requested is assumed to be 'encrypt + * and sign' * @param {Boolean} base64 (optional) The data will be interpreted as - * base64 encoded data - * @param {Boolean} armor (optional) Request the output as armored block + * base64 encoded data. + * @param {Boolean} armor (optional) Request the output as armored block. * @param {Boolean} wildcard (optional) If true, recipient information will - * not be added to the message - * @param {Object} additional use additional gpg options - * (refer to src/permittedOperations) - * @returns {Promise} Encrypted message: - * data: The encrypted message - * base64: Boolean indicating whether data is base64 encoded. + * not be added to the message. + * @param {Object} additional use additional valid gpg options as defined + * in {@link permittedOperations} + * @returns {Promise} Object containing the encrypted + * message and additional info. * @async */ encrypt(data, publicKeys, secretKeys, base64=false, armor=true, @@ -105,28 +160,12 @@ export class GpgME { } /** - * Decrypt a Message + * Decrypts a Message * @param {String|Object} data text/data to be decrypted. Accepts Strings * and Objects with a getText method * @param {Boolean} base64 (optional) false if the data is an armored block, * true if it is base64 encoded binary data - * @returns {Promise} result: Decrypted Message and information - * @returns {String} result.data: The decrypted data. - * @returns {Boolean} result.base64: indicating whether data is base64 - * encoded. - * @returns {Boolean} result.is_mime: Indicating whether the data is a MIME - * object. - * @returns {String} result.file_name: The optional original file name - * @returns {Object} message.signatures Verification details for signatures: - * @returns {Boolean} message.signatures.all_valid: true if all signatures - * are valid - * @returns {Number} message.signatures.count: Number of signatures found - * @returns {Number} message.signatures.failures Number of invalid - * signatures - * @returns {Array} message.signatures.signatures. Two arrays - * (good & bad) of {@link GPGME_Signature} objects, offering further - * information. - * + * @returns {Promise} Decrypted Message and information * @async */ decrypt(data, base64=false){ @@ -169,16 +208,13 @@ export class GpgME { /** * Sign a Message * @param {String|Object} data text/data to be signed. Accepts Strings - * and Objects with a gettext methos - * @param {GPGME_Key|String|Array|Array} keys The - * key/keys to use for signing - * @param {*} mode The signing mode. Currently supported: - * 'clearsign': (default) The Message is embedded into the signature - * 'detached': The signature is stored separately - * @param {*} base64 input is considered base64 - * @returns {Promise} - * data: The resulting data. Includes the signature in clearsign mode - * signature: The detached signature (if in detached mode) + * and Objects with a getText method. + * @param {inputKeys} keys The key/keys to use for signing + * @param {String} mode The signing mode. Currently supported: + * 'clearsign':The Message is embedded into the signature; + * 'detached': The signature is stored separately + * @param {Boolean} base64 input is considered base64 + * @returns {Promise} * @async */ sign(data, keys, mode='clearsign', base64=false) { @@ -221,20 +257,12 @@ export class GpgME { /** * Verifies data. * @param {String|Object} data text/data to be verified. Accepts Strings - * and Objects with a gettext method + * and Objects with a getText method * @param {String} (optional) A detached signature. If not present, opaque * mode is assumed * @param {Boolean} (optional) Data and signature are base64 encoded - * // TODO verify if signature really is assumed to be base64 - * @returns {Promise} result: - * @returns {Boolean} result.data: The verified data - * @returns {Boolean} result.is_mime: The message claims it is MIME - * @returns {String} result.file_name: The optional filename of the message - * @returns {Boolean} result.all_valid: true if all signatures are valid - * @returns {Number} result.count: Number of signatures found - * @returns {Number} result.failures Number of unsuccessful signatures - * @returns {Array} result.signatures. Two arrays (good & bad) of - * {@link GPGME_Signature} objects, offering further information. + * @returns {Promise} + *@async */ verify(data, signature, base64 = false){ let msg = createMessage('verify'); @@ -275,7 +303,10 @@ export class GpgME { /** * Sets the data of the message, setting flags according on the data type * @param {GPGME_Message} message The message where this data will be set - * @param {*} data The data to enter + * @param { String| Object } data The data to enter. Expects either a string of + * data, or an object with a getText method + * @returns {undefined| GPGME_Error} Error if not successful, nothing otherwise + * @private */ function putData(message, data){ if (!message || !(message instanceof GPGME_Message) ) { @@ -301,6 +332,11 @@ function putData(message, data){ } } +/** + * Parses, validates and converts incoming objects into signatures. + * @param {Array} sigs + * @returns {signatureDetails} Details about the signatures + */ function collectSignatures(sigs){ if (!Array.isArray(sigs)){ return gpgme_error('SIG_NO_SIGS'); diff --git a/lang/js/src/index.js b/lang/js/src/index.js index 6db2873..dc613fc 100644 --- a/lang/js/src/index.js +++ b/lang/js/src/index.js @@ -27,8 +27,8 @@ import { gpgme_error } from './Errors'; import { Connection } from './Connection'; /** - * Tests nativeMessaging once and returns a GpgME object if successful. - * @returns {GpgME | Error} + * Initializes gpgme.js by testing the nativeMessaging connection once. + * @returns {Promise | GPGME_Error} * * @async */ diff --git a/lang/js/src/permittedOperations.js b/lang/js/src/permittedOperations.js index e7f5396..0b9c891 100644 --- a/lang/js/src/permittedOperations.js +++ b/lang/js/src/permittedOperations.js @@ -22,27 +22,30 @@ */ /** - * Definition of the possible interactions with gpgme-json. - * operation: - required: Array - name The name of the property - allowed: Array of allowed types. Currently accepted values: - ['number', 'string', 'boolean', 'Uint8Array'] - array_allowed: Boolean. If the value can be an array of the above - allowed_data: If present, restricts to the given value - optional: Array - see 'required', with these parameters not being mandatory for a - complete message - pinentry: boolean If a pinentry dialog is expected, and a timeout of - 5000 ms would be too short - answer: - type: - the properties expected and their type, eg: {'data':'string'} - } - } -*/ + * @typedef {Object} messageProperty + * A message Property is defined by it's key. + * @property {Array} allowed Array of allowed types. + * Currently accepted values are 'number', 'string', 'boolean'. + * @property {Boolean} array_allowed If the value can be an array of types + * defined in allowed + * @property {} allowed_data (optional) restricts to the given values + */ +/** + * Definition of the possible interactions with gpgme-json. + * @param {Object} operation Each operation is named by a key and contains + * the following properties: + * @property {messageProperty} required An object with all required parameters + * @property {messageProperty} optional An object with all optional parameters + * @property {Boolean} pinentry (optional) If true, a password dialog is + * expected, thus a connection tuimeout is not advisable + * @property {Object} answer The definition on what to expect as answer, if the + * answer is not an error + * @property {Array} answer.type the type(s) as reported by gpgme-json. + * @property {Object} answer.data key-value combinations of expected properties + * of an answer and their type ('boolean', 'string', object) + @const +*/ export const permittedOperations = { encrypt: { pinentry: true, //TODO only with signing_keys ----------------------------------------------------------------------- Summary of changes: lang/js/README | 29 +++++--- lang/js/src/Connection.js | 58 +++++++++++---- lang/js/src/Errors.js | 18 ++++- lang/js/src/Helpers.js | 34 ++++++--- lang/js/src/Key.js | 145 +++++++++++++++++++++++++++--------- lang/js/src/Keyring.js | 132 ++++++++++++++++++++------------- lang/js/src/Message.js | 52 ++++++++----- lang/js/src/Signature.js | 29 ++++---- lang/js/src/gpgmejs.js | 146 +++++++++++++++++++++++-------------- lang/js/src/index.js | 4 +- lang/js/src/permittedOperations.js | 43 ++++++----- 11 files changed, 456 insertions(+), 234 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 10 14:41:42 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Tue, 10 Jul 2018 14:41:42 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-49-g42a0424 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via 42a0424b7cf2b7d3ebb80c8d70eadb21c67b620d (commit) via fd411b524fd1d4617682f416d937be8ace410a6f (commit) from 7e6e15a8650ec232a1e07624b20bed9a4475fc50 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 42a0424b7cf2b7d3ebb80c8d70eadb21c67b620d Author: Andre Heinecke Date: Tue Jul 10 14:26:12 2018 +0200 Convert common to cpp and clean it up * src/Makefile.am: Remove config-dialog.c * src/common.c, src/common.cpp: Cppify, cleanup. * src/config-dialog.c: Remove it. * src/gpgoladdin.cpp (GetCustomUI_MIME): Use normal utf8_to_wchar. diff --git a/src/Makefile.am b/src/Makefile.am index 500e286..d3d8b19 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,9 +30,8 @@ gpgol_SOURCES = \ addin-options.cpp addin-options.h \ application-events.cpp \ attachment.h attachment.cpp \ - common.h common.c \ + common.h common.cpp \ common_indep.h common_indep.c \ - config-dialog.c \ cpphelp.cpp cpphelp.h \ cryptcontroller.cpp cryptcontroller.h \ dialogs.h \ diff --git a/src/common.c b/src/common.cpp similarity index 61% rename from src/common.c rename to src/common.cpp index a9ac04b..629690d 100644 --- a/src/common.c +++ b/src/common.cpp @@ -37,9 +37,10 @@ #include #include "common.h" - #include "dialogs.h" +#include + HINSTANCE glob_hinst = NULL; void @@ -48,202 +49,6 @@ set_global_hinstance (HINSTANCE hinst) glob_hinst = hinst; } -/* Center the given window with the desktop window as the - parent window. */ -void -center_window (HWND childwnd, HWND style) -{ - HWND parwnd; - RECT rchild, rparent; - HDC hdc; - int wchild, hchild, wparent, hparent; - int wscreen, hscreen, xnew, ynew; - int flags = SWP_NOSIZE | SWP_NOZORDER; - - parwnd = GetDesktopWindow (); - GetWindowRect (childwnd, &rchild); - wchild = rchild.right - rchild.left; - hchild = rchild.bottom - rchild.top; - - GetWindowRect (parwnd, &rparent); - wparent = rparent.right - rparent.left; - hparent = rparent.bottom - rparent.top; - - hdc = GetDC (childwnd); - wscreen = GetDeviceCaps (hdc, HORZRES); - hscreen = GetDeviceCaps (hdc, VERTRES); - ReleaseDC (childwnd, hdc); - xnew = rparent.left + ((wparent - wchild) / 2); - if (xnew < 0) - xnew = 0; - else if ((xnew+wchild) > wscreen) - xnew = wscreen - wchild; - ynew = rparent.top + ((hparent - hchild) / 2); - if (ynew < 0) - ynew = 0; - else if ((ynew+hchild) > hscreen) - ynew = hscreen - hchild; - if (style == HWND_TOPMOST || style == HWND_NOTOPMOST) - flags = SWP_NOMOVE | SWP_NOSIZE; - SetWindowPos (childwnd, style? style : NULL, xnew, ynew, 0, 0, flags); -} - - -/* Return the system's bitmap of the check bar used which check boxes. - If CHECKED is set, this check mark is returned; if it is not set, - the one used for not-checked is returned. May return NULL on - error. Taken from an example in the platform reference. - - Not used as of now. */ -HBITMAP -get_system_check_bitmap (int checked) -{ - COLORREF bg_color; - HBRUSH bg_brush, saved_dst_brush; - HDC src_dc, dst_dc; - WORD xsize, ysize; - HBITMAP result, saved_dst_bitmap, saved_src_bitmap, checkboxes; - BITMAP bitmap; - RECT rect; - - bg_color = GetSysColor (COLOR_MENU); - bg_brush = CreateSolidBrush (bg_color); - - src_dc = CreateCompatibleDC (NULL); - dst_dc = CreateCompatibleDC (src_dc); - - xsize = GetSystemMetrics (SM_CXMENUCHECK); - ysize = GetSystemMetrics (SM_CYMENUCHECK); - result = CreateCompatibleBitmap(src_dc, xsize, ysize); - - saved_dst_brush = SelectObject (dst_dc, bg_brush); - saved_dst_bitmap = SelectObject (dst_dc, result); - - PatBlt (dst_dc, 0, 0, xsize, ysize, PATCOPY); - - checkboxes = LoadBitmap (NULL, (LPTSTR)OBM_CHECKBOXES); - - saved_src_bitmap = SelectObject (src_dc, checkboxes); - - GetObject (checkboxes, sizeof (BITMAP), &bitmap); - rect.top = 0; - rect.bottom = (bitmap.bmHeight / 3); - if (checked) - { - /* Select row 1, column 1. */ - rect.left = 0; - rect.right = (bitmap.bmWidth / 4); - } - else - { - /* Select row 1, column 2. */ - rect.left = (bitmap.bmWidth / 4); - rect.right = (bitmap.bmWidth / 4) * 2; - } - - if ( ((rect.right - rect.left) > (int)xsize) - || ((rect.bottom - rect.top) > (int)ysize) ) - StretchBlt (dst_dc, 0, 0, xsize, ysize, src_dc, rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top, SRCCOPY); - else - BitBlt (dst_dc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, - src_dc, rect.left, rect.top, SRCCOPY); - - SelectObject (src_dc, saved_src_bitmap); - SelectObject (dst_dc, saved_dst_brush); - result = SelectObject (dst_dc, saved_dst_bitmap); - - DeleteObject (bg_brush); - DeleteObject (src_dc); - DeleteObject (dst_dc); - return result; -} - -/* Return the path to a file that should be worked with. - Returns a malloced string (UTF-8) on success. - HWND is the current Window. - Title is a UTF-8 encoded string containing the - dialog title and may be NULL. - On error (i.e. cancel) NULL is returned. */ -char * -get_open_filename (HWND root, const char *title) -{ - OPENFILENAMEW ofn; - wchar_t fname[MAX_PATH+1]; - wchar_t *wTitle = NULL; - - if (title) - { - wTitle = utf8_to_wchar2 (title, strlen(title)); - } - memset (fname, 0, sizeof (fname)); - - /* Set up the ofn structure */ - memset (&ofn, 0, sizeof (ofn)); - ofn.lStructSize = sizeof (ofn); - ofn.hwndOwner = root; - ofn.lpstrFile = fname; - ofn.nMaxFile = MAX_PATH; - ofn.lpstrTitle = wTitle; - ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; - - if (GetOpenFileNameW (&ofn)) - { - xfree (wTitle); - return wchar_to_utf8_2 (fname, MAX_PATH); - } - xfree (wTitle); - return NULL; -} - - -/* Return a filename to be used for saving an attachment. Returns a - malloced string on success. HWND is the current Window and SRCNAME - the filename to be used as suggestion. On error (i.e. cancel) NULL - is returned. */ -char * -get_save_filename (HWND root, const char *srcname) -{ - char filter[21] = "All Files (*.*)\0*.*\0\0"; - char fname[MAX_PATH+1]; - char filterBuf[32]; - char* extSep; - OPENFILENAME ofn; - - memset (fname, 0, sizeof (fname)); - memset (filterBuf, 0, sizeof (filterBuf)); - strncpy (fname, srcname, MAX_PATH-1); - fname[MAX_PATH] = 0; - - if ((extSep = strrchr (srcname, '.')) && strlen (extSep) <= 4) - { - /* Windows removes the file extension by default so we - need to set the first filter to the file extension. - */ - strcpy (filterBuf, extSep); - strcpy (filterBuf + strlen (filterBuf) + 1, extSep); - memcpy (filterBuf + strlen (extSep) * 2 + 2, filter, 21); - } - else - memcpy (filterBuf, filter, 21); - - - memset (&ofn, 0, sizeof (ofn)); - ofn.lStructSize = sizeof (ofn); - ofn.hwndOwner = root; - ofn.lpstrFile = fname; - ofn.nMaxFile = MAX_PATH; - ofn.lpstrFileTitle = NULL; - ofn.nMaxFileTitle = 0; - ofn.Flags |= OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; - ofn.lpstrTitle = _("GpgOL - Save attachment"); - ofn.lpstrFilter = filterBuf; - - if (GetSaveFileName (&ofn)) - return xstrdup (fname); - return NULL; -} - void bring_to_front (HWND wid) { @@ -278,97 +83,6 @@ fatal_error (const char *format, ...) } -/* This is a helper function to load a Windows function from either of - one DLLs. */ -static HRESULT -w32_shgetfolderpath (HWND a, int b, HANDLE c, DWORD d, LPSTR e) -{ - static int initialized; - static HRESULT (WINAPI * func)(HWND,int,HANDLE,DWORD,LPSTR); - - if (!initialized) - { - static char *dllnames[] = { "shell32.dll", "shfolder.dll", NULL }; - void *handle; - int i; - - initialized = 1; - - for (i=0, handle = NULL; !handle && dllnames[i]; i++) - { - handle = LoadLibrary (dllnames[i]); - if (handle) - { - func = (HRESULT (WINAPI *)(HWND,int,HANDLE,DWORD,LPSTR)) - GetProcAddress (handle, "SHGetFolderPathA"); - if (!func) - { - FreeLibrary (handle); - handle = NULL; - } - } - } - } - - if (func) - return func (a,b,c,d,e); - else - return -1; -} - - - -/* Same as above, but only convert the first LEN wchars. */ -char * -wchar_to_utf8_2 (const wchar_t *string, size_t len) -{ - int n; - char *result; - - /* Note, that CP_UTF8 is not defined in Windows versions earlier - than NT.*/ - n = WideCharToMultiByte (CP_UTF8, 0, string, len, NULL, 0, NULL, NULL); - if (n < 0) - return NULL; - - result = xmalloc (n+1); - n = WideCharToMultiByte (CP_UTF8, 0, string, len, result, n, NULL, NULL); - if (n < 0) - { - xfree (result); - return NULL; - } - return result; -} - - -/* Same as above but convert only the first LEN characters. STRING - must be at least LEN characters long. */ -wchar_t * -utf8_to_wchar2 (const char *string, size_t len) -{ - int n; - wchar_t *result; - - n = MultiByteToWideChar (CP_UTF8, 0, string, len, NULL, 0); - if (n < 0) - return NULL; - - result = xmalloc ((n+1) * sizeof *result); - n = MultiByteToWideChar (CP_UTF8, 0, string, len, result, n); - if (n < 0) - { - xfree (result); - return NULL; - } - result[n] = 0; - return result; -} - - - - - /* Helper for read_w32_registry_string(). */ static HKEY get_root_key(const char *root) @@ -394,167 +108,97 @@ get_root_key(const char *root) return root_key; } -/* Return a string from the Win32 Registry or NULL in case of error. - Caller must release the return value. A NULL for root is an alias - for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. NOTE: The value - is allocated with a plain malloc() - use free() and not the usual - xfree(). */ -char * -read_w32_registry_string (const char *root, const char *dir, const char *name) +static std::string +readRegStr (const char *root, const char *dir, const char *name) { - HKEY root_key, key_handle; - DWORD n1, nbytes, type; - char *result = NULL; +#ifndef _WIN32 + (void)root; (void)dir; (void)name; + return std::string(); +#else - if ( !(root_key = get_root_key(root) ) ) - return NULL; - - if( RegOpenKeyEx( root_key, dir, 0, KEY_READ, &key_handle ) ) - { - if (root) - return NULL; /* no need for a RegClose, so return direct */ - /* It seems to be common practise to fall back to HKLM. */ - if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) ) - return NULL; /* still no need for a RegClose, so return direct */ - } + HKEY root_key, key_handle; + DWORD n1, nbytes, type; + std::string ret; - nbytes = 1; - if( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) ) { - if (root) - goto leave; - /* Try to fallback to HKLM also vor a missing value. */ - RegCloseKey (key_handle); - if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) ) - return NULL; /* Nope. */ - if (RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes)) - goto leave; - } - result = malloc( (n1=nbytes+1) ); - if( !result ) - goto leave; - if( RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ) ) { - free(result); result = NULL; - goto leave; - } - result[nbytes] = 0; /* make sure it is really a string */ - if (type == REG_EXPAND_SZ && strchr (result, '%')) { - char *tmp; - - n1 += 1000; - tmp = malloc (n1+1); - if (!tmp) - goto leave; - nbytes = ExpandEnvironmentStrings (result, tmp, n1); - if (nbytes && nbytes > n1) { - free (tmp); - n1 = nbytes; - tmp = malloc (n1 + 1); - if (!tmp) - goto leave; - nbytes = ExpandEnvironmentStrings (result, tmp, n1); - if (nbytes && nbytes > n1) { - free (tmp); /* oops - truncated, better don't expand at all */ - goto leave; - } - tmp[nbytes] = 0; - free (result); - result = tmp; - } - else if (nbytes) { /* okay, reduce the length */ - tmp[nbytes] = 0; - free (result); - result = malloc (strlen (tmp)+1); - if (!result) - result = tmp; - else { - strcpy (result, tmp); - free (tmp); - } - } - else { /* error - don't expand */ - free (tmp); + if (!(root_key = get_root_key(root))) { + return ret; } - } - - leave: - RegCloseKey( key_handle ); - return result; -} - - -/* Get the standard home directory. In general this function should - not be used as it does not consider a registry value or the - GNUPGHOME environment variable. Please use default_homedir(). */ -static const char * -standard_homedir (void) -{ - static char *dir; - - if (!dir) - { - char path[MAX_PATH]; - - /* It might be better to use LOCAL_APPDATA because this is - defined as "non roaming" and thus more likely to be kept - locally. For private keys this is desired. However, given - that many users copy private keys anyway forth and back, - using a system roaming services might be better than to let - them do it manually. A security conscious user will anyway - use the registry entry to have better control. */ - if (w32_shgetfolderpath (NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE, - NULL, 0, path) >= 0) - { - char *tmp = malloc (strlen (path) + 6 + 1); - strcpy (tmp, path); - strcat (tmp, "\\gnupg"); + if (RegOpenKeyExA(root_key, dir, 0, KEY_READ, &key_handle)) { + if (root) { + /* no need for a RegClose, so return direct */ + return ret; + } + /* Fallback to HKLM */ - dir = tmp; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle)) { + return ret; + } + } - /* Try to create the directory if it does not yet exists. */ - if (access (dir, F_OK)) - CreateDirectory (dir, NULL); + nbytes = 1; + if (RegQueryValueExA(key_handle, name, 0, nullptr, nullptr, &nbytes)) { + if (root) { + RegCloseKey (key_handle); + return ret; + } + /* Try to fallback to HKLM also vor a missing value. */ + RegCloseKey (key_handle); + if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle)) { + return ret; + } + if (RegQueryValueExA(key_handle, name, 0, nullptr, nullptr, &nbytes)) { + RegCloseKey(key_handle); + return ret; } - else - dir = xstrdup ("C:\\gnupg"); } - return dir; + n1 = nbytes+1; + char result[n1]; + if (RegQueryValueExA(key_handle, name, 0, &type, (LPBYTE)result, &n1)) { + RegCloseKey(key_handle); + return ret; + } + RegCloseKey(key_handle); + result[nbytes] = 0; /* make sure it is really a string */ + ret = result; + if (type == REG_EXPAND_SZ && strchr (result, '%')) { + n1 += 1000; + char tmp[n1 +1]; + + nbytes = ExpandEnvironmentStringsA(ret.c_str(), tmp, n1); + if (nbytes && nbytes > n1) { + n1 = nbytes; + char tmp2[n1 +1]; + nbytes = ExpandEnvironmentStringsA(result, tmp2, n1); + if (nbytes && nbytes > n1) { + /* oops - truncated, better don't expand at all */ + return ret; + } + tmp2[nbytes] = 0; + ret = tmp2; + } else if (nbytes) { /* okay, reduce the length */ + tmp[nbytes] = 0; + ret = tmp; + } + } + return ret; +#endif } - -/* Retrieve the default home directory. */ -const char * -default_homedir (void) +/* Return a string from the Win32 Registry or NULL in case of error. + Caller must release the return value. A NULL for root is an alias + for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. NOTE: The value + is allocated with a plain malloc() - use free() and not the usual + xfree(). */ +char * +read_w32_registry_string (const char *root, const char *dir, const char *name) { - static char *dir; - - if (!dir) + const auto ret = readRegStr (root, dir, name); + if (ret.empty()) { - dir = getenv ("GNUPGHOME"); - if (!dir || !*dir) - { - char *tmp; - - tmp = read_w32_registry_string (NULL, GPG4WIN_REGKEY_3, "HomeDir"); - if (!tmp) - { - tmp = read_w32_registry_string (NULL, GPG4WIN_REGKEY_2, "HomeDir"); - } - if (tmp && !*tmp) - { - free (tmp); - tmp = NULL; - } - if (tmp) - dir = tmp; - else - dir = xstrdup (standard_homedir ()); - } - else - dir = xstrdup (dir); + return nullptr; } - - return dir; + return strdup (ret.c_str ()); } /* Return the data dir used for forms etc. Returns NULL on error. */ @@ -568,10 +212,10 @@ get_data_dir (void) instdir = get_gpg4win_dir(); if (!instdir) return NULL; - + /* Build the key: "/share/gpgol". */ #define SDDIR "\\share\\gpgol" - dname = malloc (strlen (instdir) + strlen (SDDIR) + 1); + dname = (char*) malloc (strlen (instdir) + strlen (SDDIR) + 1); if (!dname) { free (instdir); @@ -581,9 +225,9 @@ get_data_dir (void) strcpy (p, instdir); p += strlen (instdir); strcpy (p, SDDIR); - + free (instdir); - + #undef SDDIR return dname; } @@ -914,7 +558,7 @@ get_uiserver_name (void) } if (uiserver) { - name = xmalloc (strlen (dir) + strlen (uiserver) + extra_arglen + 2); + name = (char*) xmalloc (strlen (dir) + strlen (uiserver) + extra_arglen + 2); strcpy (stpcpy (stpcpy (name, dir), "\\"), uiserver); for (p = name; *p; p++) if (*p == '/') @@ -934,7 +578,7 @@ get_uiserver_name (void) { xfree (name); } - name = xmalloc (strlen (dir) + strlen (*tmp) + extra_arglen + 2); + name = (char *) xmalloc (strlen (dir) + strlen (*tmp) + extra_arglen + 2); strcpy (stpcpy (stpcpy (name, dir), "\\"), *tmp); for (p = name; *p; p++) if (*p == '/') @@ -1087,7 +731,7 @@ expand_path (const char *path) return NULL; } len += 1; - p = xcalloc (1, len+1); + p = (char *) xcalloc (1, len+1); if (!p) { return NULL; @@ -1133,7 +777,7 @@ load_config_value (HKEY hk, const char *path, const char *key, char **val) } else { - *val = xcalloc(1, size+1); + *val = (char *) xcalloc(1, size+1); ec = RegQueryValueEx (h, key, NULL, &type, (BYTE*)*val, &size); if (ec != ERROR_SUCCESS) { diff --git a/src/common.h b/src/common.h index 265955c..52099fd 100644 --- a/src/common.h +++ b/src/common.h @@ -33,6 +33,12 @@ #include +/* i18n stuff */ +#include "w32-gettext.h" +#define _(a) gettext (a) +#define N_(a) gettext_noop (a) + + /* Registry path to store plugin settings */ #define GPGOL_REGPATH "Software\\GNU\\GpgOL" @@ -47,13 +53,7 @@ extern UINT this_dll; /*-- common.c --*/ void set_global_hinstance (HINSTANCE hinst); -void center_window (HWND childwnd, HWND style); -HBITMAP get_system_check_bitmap (int checked); -char *get_save_filename (HWND root, const char *srcname); -char *get_open_filename (HWND root, const char *title); -char *utf8_to_wincp (const char *string); -const char *default_homedir (void); char *get_data_dir (void); char *get_gpg4win_dir (void); @@ -68,22 +68,6 @@ wchar_t *get_tmp_outfile (wchar_t *name, HANDLE *outHandle); wchar_t *get_pretty_attachment_name (wchar_t *path, protocol_t protocol, int signature); -/*-- recipient-dialog.c --*/ -unsigned int recipient_dialog_box (gpgme_key_t **ret_rset); -unsigned int recipient_dialog_box2 (gpgme_key_t *fnd, char **unknown, - gpgme_key_t **ret_rset); - -/*-- passphrase-dialog.c --*/ -int signer_dialog_box (gpgme_key_t *r_key, char **r_passwd, int encrypting); -gpgme_error_t passphrase_callback_box (void *opaque, const char *uid_hint, - const char *pass_info, - int prev_was_bad, int fd); -void free_decrypt_key (struct passphrase_cb_s *ctx); -const char *get_pubkey_algo_str (gpgme_pubkey_algo_t id); - -/*-- config-dialog.c --*/ -void config_dialog_box (HWND parent); - /*-- verify-dialog.c --*/ int verify_dialog_box (gpgme_protocol_t protocol, gpgme_verify_result_t res, @@ -100,18 +84,10 @@ int initialize_inspectors (void); #endif -/* i18n stuff */ -#include "w32-gettext.h" -#define _(a) gettext (a) -#define N_(a) gettext_noop (a) - - /*-- common.c --*/ void fatal_error (const char *format, ...); -char *wchar_to_utf8_2 (const wchar_t *string, size_t len); -wchar_t *utf8_to_wchar2 (const char *string, size_t len); char *read_w32_registry_string (const char *root, const char *dir, const char *name); char *percent_escape (const char *str, const char *extra); @@ -128,18 +104,11 @@ char *get_uiserver_name (void); int is_elevated (void); /*-- main.c --*/ -const void *get_128bit_session_key (void); -const void *get_64bit_session_marker (void); -void *create_initialization_vector (size_t nbytes); - void read_options (void); int write_options (void); extern int g_ol_version_major; -void log_window_hierarchy (HWND window, const char *fmt, - ...) __attribute__ ((format (printf,2,3))); - void bring_to_front (HWND wid); int gpgol_message_box (HWND parent, const char *utf8_text, diff --git a/src/config-dialog.c b/src/config-dialog.c deleted file mode 100644 index b2663f7..0000000 --- a/src/config-dialog.c +++ /dev/null @@ -1,96 +0,0 @@ -/* config-dialog.c - * Copyright (C) 2005, 2008 g10 Code GmbH - * Copyright (C) 2003 Timo Schulz - * - * This file is part of GpgOL. - * - * GpgOL 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. - * - * GpgOL 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 Lesser 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 . - */ - -#include - -#include -#include -#include - -#include "common.h" -#include "gpgol-ids.h" -#include "dialogs.h" - -/* To avoid writing a dialog template for each language we use gettext - for the labels and hope that there is enough space in the dialog to - fit teh longest translation. */ -static void -config_dlg_set_labels (HWND dlg) -{ - static struct { int itemid; const char *label; } labels[] = { - { IDC_T_DEBUG_LOGFILE, N_("Debug output (for analysing problems)")}, - { 0, NULL} - }; - int i; - - for (i=0; labels[i].itemid; i++) - SetDlgItemText (dlg, labels[i].itemid, _(labels[i].label)); - -} - -static BOOL CALLBACK -config_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam) -{ - char name[MAX_PATH+1]; - int n; - const char *s; - - (void)lparam; - - switch (msg) - { - case WM_INITDIALOG: - center_window (dlg, 0); - s = get_log_file (); - SetDlgItemText (dlg, IDC_DEBUG_LOGFILE, s? s:""); - config_dlg_set_labels (dlg); - break; - - case WM_COMMAND: - switch (LOWORD (wparam)) - { - case IDOK: - n = GetDlgItemText (dlg, IDC_DEBUG_LOGFILE, name, MAX_PATH-1); - set_log_file (n>0?name:NULL); - EndDialog (dlg, TRUE); - break; - } - break; - } - return FALSE; -} - -/* Display GPG configuration dialog. */ -void -config_dialog_box (HWND parent) -{ -#ifndef _WIN64 - int resid; - - resid = IDD_EXT_OPTIONS; - - if (!parent) - parent = GetDesktopWindow (); - DialogBoxParam (glob_hinst, (LPCTSTR)resid, parent, config_dlg_proc, 0); -#else - (void)parent; - (void)config_dlg_proc; -#endif -} diff --git a/src/gpgoladdin.cpp b/src/gpgoladdin.cpp index b43ef6f..15fb475 100644 --- a/src/gpgoladdin.cpp +++ b/src/gpgoladdin.cpp @@ -1061,7 +1061,7 @@ GetCustomUI_MIME (BSTR RibbonID, BSTR * RibbonXml) if (buffer) { - wchar_t *wbuf = utf8_to_wchar2 (buffer, strlen(buffer)); + wchar_t *wbuf = utf8_to_wchar (buffer); xfree (buffer); *RibbonXml = SysAllocString (wbuf); xfree (wbuf); commit fd411b524fd1d4617682f416d937be8ace410a6f Author: Andre Heinecke Date: Tue Jul 10 13:47:52 2018 +0200 Remove accidentally commited dev debug -- diff --git a/src/oomhelp.cpp b/src/oomhelp.cpp index 7884752..a5822b5 100644 --- a/src/oomhelp.cpp +++ b/src/oomhelp.cpp @@ -2265,7 +2265,6 @@ get_ol_ui_language () int result = var.intVal; - log_debug ("XXXXX %i", result); VariantClear (&var); return result; } ----------------------------------------------------------------------- Summary of changes: src/Makefile.am | 3 +- src/{common.c => common.cpp} | 530 +++++++------------------------------------ src/common.h | 43 +--- src/config-dialog.c | 96 -------- src/gpgoladdin.cpp | 2 +- src/oomhelp.cpp | 1 - 6 files changed, 95 insertions(+), 580 deletions(-) rename src/{common.c => common.cpp} (61%) delete mode 100644 src/config-dialog.c hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 11 04:11:04 2018 From: cvs at cvs.gnupg.org (by NIIBE Yutaka) Date: Wed, 11 Jul 2018 04:11:04 +0200 Subject: [git] GPG-ERROR - branch, master, updated. libgpg-error-1.31-11-g0727c39 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Error codes used by GnuPG et al.". The branch, master has been updated via 0727c394562237d7e626849eae04790264e56208 (commit) via f1162767e3552d05c1255497d49de15c2d94d0b4 (commit) from 302d43a130e2364ea882474088a8b0a31bc325b9 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 0727c394562237d7e626849eae04790264e56208 Author: NIIBE Yutaka Date: Wed Jul 11 10:56:30 2018 +0900 build: Use AX_CC_FOR_BUILD and EXEEXT. * configure.ac (AX_CC_FOR_BUILD): New. * doc/Makefile.am: Use EXEEXT and EXEEXT_FOR_BUILD. * m4/ac_prog_cc_for_build.m4: Remove. * m4/ax_cc_for_build.m4: New. -- Suggested-by: Michael Haubenwallner Fixes-commit: 6eb80abcde5ad776379069871e4156b28ef69712 Signed-off-by: NIIBE Yutaka diff --git a/configure.ac b/configure.ac index 5c69dce..129cb61 100644 --- a/configure.ac +++ b/configure.ac @@ -126,17 +126,7 @@ LT_LANG([Windows Resource]) # We need to compile and run a program on the build machine. -dnl The AC_PROG_CC_FOR_BUILD macro in the AC archive is broken for -dnl autoconf 2.57. -dnl AC_PROG_CC_FOR_BUILD -AC_MSG_CHECKING(for cc for build) -if test "$cross_compiling" = "yes"; then - CC_FOR_BUILD="${CC_FOR_BUILD-cc}" -else - CC_FOR_BUILD="${CC_FOR_BUILD-$CC}" -fi -AC_MSG_RESULT($CC_FOR_BUILD) -AC_ARG_VAR(CC_FOR_BUILD,[build system C compiler]) +AX_CC_FOR_BUILD AH_BOTTOM([ /* Force using of NLS for W32 even if no libintl has been found. This is diff --git a/doc/Makefile.am b/doc/Makefile.am index d9d5d15..9090067 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -38,20 +38,15 @@ myman_pages = gpg-error-config.1 man_MANS = $(myman_pages) if CROSS_COMPILING -YAT2M_CMD = ./yat2m-for-build -YAT2M_DEP = yat2m-for-build -CLEANFILES += yat2m-for-build +YAT2M_CMD = ./yat2m-for-build$(EXEEXT_FOR_BUILD) +YAT2M_DEP = yat2m-for-build$(EXEEXT_FOR_BUILD) +CLEANFILES += yat2m-for-build$(EXEEXT_FOR_BUILD) -yat2m-for-build: yat2m.c - $(CC_FOR_BUILD) -o $@ $(srcdir)/yat2m.c +yat2m-for-build$(EXEEXT_FOR_BUILD): yat2m.c + $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $@ $(srcdir)/yat2m.c else -if HAVE_W32_SYSTEM -YAT2M_CMD = ./yat2m.exe -YAT2M_DEP = yat2m.exe -else -YAT2M_CMD = ./yat2m -YAT2M_DEP = yat2m -endif +YAT2M_CMD = ./yat2m$(EXEEXT) +YAT2M_DEP = yat2m$(EXEEXT) endif yat2m-stamp: $(myman_sources) $(srcdir)/version.texi diff --git a/m4/ac_prog_cc_for_build.m4 b/m4/ac_prog_cc_for_build.m4 deleted file mode 100644 index 32329c7..0000000 --- a/m4/ac_prog_cc_for_build.m4 +++ /dev/null @@ -1,149 +0,0 @@ -dnl Available from the GNU Autoconf Macro Archive at: -dnl https://www.gnu.org/software/ac-archive/htmldoc/ac_prog_cc_for_build.html -dnl -dnl All content of this archive is free software; -dnl you can redistribute it and/or modify it under the terms of the GNU -dnl General Public License as published by the Free Software Foundation; -dnl either version 2, or (at your option) any later version. -dnl -dnl As a special exception, the respective Autoconf Macro's copyright -dnl owner gives unlimited permission to copy, distribute and modify the -dnl configure scripts that are the output of Autoconf when processing the -dnl Macro. You need not follow the terms of the GNU General Public License -dnl when using or distributing such scripts, even though portions of the -dnl text of the Macro appear in them. The GNU General Public License (GPL) -dnl does govern all other use of the material that constitutes the -dnl Autoconf Macro. -dnl -dnl This special exception to the GPL applies to versions of the Autoconf -dnl Macro released by the GNU Autoconf Macro Archive. When you make and -dnl distribute a modified version of the Autoconf Macro, you may extend -dnl this special exception to the GPL to apply to your modified version as -dnl well. - -dnl Synopsis AC_PROG_CC_FOR_BUILD -dnl -dnl This macro searches for a C compiler that generates native -dnl executables, that is a C compiler that surely is not a cross-compiler. -dnl This can be useful if you have to generate source code at compile-time -dnl like for example GCC does. -dnl -dnl The macro sets the CC_FOR_BUILD and CPP_FOR_BUILD macros to anything -dnl needed to compile or link (CC_FOR_BUILD) and preprocess -dnl (CPP_FOR_BUILD). The value of these variables can be overridden by -dnl the user by specifying a compiler with an environment variable (like -dnl you do for standard CC). -dnl -dnl It also sets BUILD_EXEEXT and BUILD_OBJEXT to the executable and -dnl object file extensions for the build platform, and GCC_FOR_BUILD -dnl to `yes' if the compiler we found is GCC. All these variables but -dnl GCC_FOR_BUILD are substituted in the Makefile. -dnl -dnl Author Paolo Bonzini -dnl -AC_DEFUN([AC_PROG_CC_FOR_BUILD], [dnl -AC_REQUIRE([AC_PROG_CC])dnl -AC_REQUIRE([AC_PROG_CPP])dnl -AC_REQUIRE([AC_EXEEXT])dnl -AC_REQUIRE([AC_CANONICAL_SYSTEM])dnl -dnl -pushdef([AC_TRY_COMPILER], [ -cat > conftest.$ac_ext << EOF -#line __oline__ "configure" -#include "confdefs.h" -[$1] -EOF -# If we can't run a trivial program, we are probably using a cross -compiler. -# Fail miserably. -if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} && (./conftest; -exit) 2>/dev/null; then - [$2]=yes -else - echo "configure: failed program was:" >&AC_FD_CC - cat conftest.$ac_ext >&AC_FD_CC - [$2]=no -fi -[$3]=no -rm -fr conftest*])dnl - -dnl Use the standard macros, but make them use other variable names -dnl -pushdef([cross_compiling], [#])dnl -pushdef([ac_cv_prog_CPP], ac_cv_build_prog_CPP)dnl -pushdef([ac_cv_prog_gcc], ac_cv_build_prog_gcc)dnl -pushdef([ac_cv_prog_cc_works], ac_cv_build_prog_cc_works)dnl -pushdef([ac_cv_prog_cc_cross], ac_cv_build_prog_cc_cross)dnl -pushdef([ac_cv_prog_cc_g], ac_cv_build_prog_cc_g)dnl -pushdef([ac_cv_exeext], ac_cv_build_exeext)dnl -pushdef([ac_cv_objext], ac_cv_build_objext)dnl -pushdef([ac_exeext], ac_build_exeext)dnl -pushdef([ac_objext], ac_build_objext)dnl -pushdef([CC], CC_FOR_BUILD)dnl -pushdef([CPP], CPP_FOR_BUILD)dnl -pushdef([CFLAGS], CFLAGS_FOR_BUILD)dnl -pushdef([CPPFLAGS], CPPFLAGS_FOR_BUILD)dnl -pushdef([host], build)dnl -pushdef([host_alias], build_alias)dnl -pushdef([host_cpu], build_cpu)dnl -pushdef([host_vendor], build_vendor)dnl -pushdef([host_os], build_os)dnl -pushdef([ac_cv_host], ac_cv_build)dnl -pushdef([ac_cv_host_alias], ac_cv_build_alias)dnl -pushdef([ac_cv_host_cpu], ac_cv_build_cpu)dnl -pushdef([ac_cv_host_vendor], ac_cv_build_vendor)dnl -pushdef([ac_cv_host_os], ac_cv_build_os)dnl -pushdef([ac_cpp], ac_build_cpp)dnl -pushdef([ac_compile], ac_build_compile)dnl -pushdef([ac_link], ac_build_link)dnl - -dnl Defeat the anti-duplication mechanism -dnl -dnl undefine([AC_PROVIDE_AC_PROG_CPP])dnl -dnl undefine([AC_PROVIDE_AC_PROG_C])dnl -dnl undefine([AC_PROVIDE_AC_EXEEXT])dnl - -AC_PROG_CC -AC_PROG_CPP -AC_EXEEXT - -dnl Restore the old definitions -dnl -popdef([AC_TRY_COMPILER])dnl -popdef([ac_link])dnl -popdef([ac_compile])dnl -popdef([ac_cpp])dnl -popdef([ac_cv_host_os])dnl -popdef([ac_cv_host_vendor])dnl -popdef([ac_cv_host_cpu])dnl -popdef([ac_cv_host_alias])dnl -popdef([ac_cv_host])dnl -popdef([host_os])dnl -popdef([host_vendor])dnl -popdef([host_cpu])dnl -popdef([host_alias])dnl -popdef([host])dnl -popdef([CPPFLAGS])dnl -popdef([CFLAGS])dnl -popdef([CPP])dnl -popdef([CC])dnl -popdef([ac_objext])dnl -popdef([ac_exeext])dnl -popdef([ac_cv_objext])dnl -popdef([ac_cv_exeext])dnl -popdef([ac_cv_prog_cc_g])dnl -popdef([ac_cv_prog_cc_works])dnl -popdef([ac_cv_prog_cc_cross])dnl -popdef([ac_cv_prog_gcc])dnl -popdef([ac_cv_prog_CPP])dnl -popdef([cross_compiling])dnl - -dnl Finally, set Makefile variables -dnl -BUILD_EXEEXT=$ac_build_exeext -BUILD_OBJEXT=$ac_build_objext -AC_SUBST(BUILD_EXEEXT)dnl -AC_SUBST(BUILD_OBJEXT)dnl -AC_SUBST([CFLAGS_FOR_BUILD])dnl -AC_SUBST([CPPFLAGS_FOR_BUILD])dnl -]) diff --git a/m4/ax_cc_for_build.m4 b/m4/ax_cc_for_build.m4 new file mode 100644 index 0000000..c62ffad --- /dev/null +++ b/m4/ax_cc_for_build.m4 @@ -0,0 +1,77 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_cc_for_build.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CC_FOR_BUILD +# +# DESCRIPTION +# +# Find a build-time compiler. Sets CC_FOR_BUILD and EXEEXT_FOR_BUILD. +# +# LICENSE +# +# Copyright (c) 2010 Reuben Thomas +# Copyright (c) 1999 Richard Henderson +# +# This program 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. +# +# This program 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 . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 3 + +dnl Get a default for CC_FOR_BUILD to put into Makefile. +AC_DEFUN([AX_CC_FOR_BUILD], +[# Put a plausible default for CC_FOR_BUILD in Makefile. +if test -z "$CC_FOR_BUILD"; then + if test "x$cross_compiling" = "xno"; then + CC_FOR_BUILD='$(CC)' + else + CC_FOR_BUILD=gcc + fi +fi +AC_SUBST(CC_FOR_BUILD) +# Also set EXEEXT_FOR_BUILD. +if test "x$cross_compiling" = "xno"; then + EXEEXT_FOR_BUILD='$(EXEEXT)' +else + AC_CACHE_CHECK([for build system executable suffix], bfd_cv_build_exeext, + [rm -f conftest* + echo 'int main () { return 0; }' > conftest.c + bfd_cv_build_exeext= + ${CC_FOR_BUILD} -o conftest conftest.c 1>&5 2>&5 + for file in conftest.*; do + case $file in + *.c | *.o | *.obj | *.ilk | *.pdb) ;; + *) bfd_cv_build_exeext=`echo $file | sed -e s/conftest//` ;; + esac + done + rm -f conftest* + test x"${bfd_cv_build_exeext}" = x && bfd_cv_build_exeext=no]) + EXEEXT_FOR_BUILD="" + test x"${bfd_cv_build_exeext}" != xno && EXEEXT_FOR_BUILD=${bfd_cv_build_exeext} +fi +AC_SUBST(EXEEXT_FOR_BUILD)])dnl commit f1162767e3552d05c1255497d49de15c2d94d0b4 Author: NIIBE Yutaka Date: Wed Jul 11 10:54:09 2018 +0900 doc: Now, yat2m is a standard tool. * configure.ac (YAT2M, HAVE_YAT2M): Remove. * doc/Makefile.am: Always use yat2m which comes with this source. -- Suggested-by: Michael Haubenwallner Fixes-commit: 4dc6d4d2067c726cdb13593bf151637319ff65e6 Signed-off-by: NIIBE Yutaka diff --git a/configure.ac b/configure.ac index 9a462dc..5c69dce 100644 --- a/configure.ac +++ b/configure.ac @@ -138,10 +138,6 @@ fi AC_MSG_RESULT($CC_FOR_BUILD) AC_ARG_VAR(CC_FOR_BUILD,[build system C compiler]) -AC_PATH_PROG(YAT2M, yat2m) -AC_ARG_VAR(YAT2M, [tool to convert texi to man pages]) -AM_CONDITIONAL(HAVE_YAT2M, test -n "$ac_cv_path_YAT2M") - AH_BOTTOM([ /* Force using of NLS for W32 even if no libintl has been found. This is okay because we have our own gettext implementation for W32. */ diff --git a/doc/Makefile.am b/doc/Makefile.am index 6f3e5a1..d9d5d15 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -37,10 +37,6 @@ myman_pages = gpg-error-config.1 man_MANS = $(myman_pages) -if HAVE_YAT2M -YAT2M_CMD = $(YAT2M) -YAT2M_DEP = $(YAT2M) -else if CROSS_COMPILING YAT2M_CMD = ./yat2m-for-build YAT2M_DEP = yat2m-for-build @@ -57,7 +53,6 @@ YAT2M_CMD = ./yat2m YAT2M_DEP = yat2m endif endif -endif yat2m-stamp: $(myman_sources) $(srcdir)/version.texi @rm -f yat2m-stamp.tmp ----------------------------------------------------------------------- Summary of changes: configure.ac | 16 +---- doc/Makefile.am | 24 +++----- m4/ac_prog_cc_for_build.m4 | 149 --------------------------------------------- m4/ax_cc_for_build.m4 | 77 +++++++++++++++++++++++ 4 files changed, 85 insertions(+), 181 deletions(-) delete mode 100644 m4/ac_prog_cc_for_build.m4 create mode 100644 m4/ax_cc_for_build.m4 hooks/post-receive -- Error codes used by GnuPG et al. http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 11 08:35:44 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Wed, 11 Jul 2018 08:35:44 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-51-g7e76531 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via 7e76531304ec9fbd5227ed511cea0f0df68fa9e0 (commit) via df2699ee2678466fbf5799a385f9a9c8d9bb66ee (commit) from 42a0424b7cf2b7d3ebb80c8d70eadb21c67b620d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 7e76531304ec9fbd5227ed511cea0f0df68fa9e0 Author: Andre Heinecke Date: Wed Jul 11 08:32:57 2018 +0200 Abort attachment process chain in case of error * src/mail.cpp (add_attachments_o): Don't continue with attachment processing if something failed. -- This should make the errors clearer and avoid undefined behavior in case e.g. obtaining an attachment tmp name fails. GnuPG-Bug-Id: T4063 diff --git a/src/mail.cpp b/src/mail.cpp index aaa15c5..6c74633 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -647,9 +647,10 @@ static int add_attachments_o(LPDISPATCH mail, std::vector > attachments) { - int err = 0; + bool anyError = false; for (auto att: attachments) { + int err = 0; if (att->get_display_name().empty()) { log_error ("%s:%s: Ignoring attachment without display name.", @@ -660,13 +661,19 @@ add_attachments_o(LPDISPATCH mail, HANDLE hFile; wchar_t* wchar_file = get_tmp_outfile (wchar_name, &hFile); - if (copy_attachment_to_file (att, hFile)) + if (!wchar_file) + { + log_error ("%s:%s: Failed to obtain a tmp filename for: %s", + SRCNAME, __func__, att->get_display_name().c_str()); + err = 1; + } + if (!err && copy_attachment_to_file (att, hFile)) { log_error ("%s:%s: Failed to copy attachment %s to temp file", SRCNAME, __func__, att->get_display_name().c_str()); err = 1; } - if (add_oom_attachment (mail, wchar_file, wchar_name)) + if (!err && add_oom_attachment (mail, wchar_file, wchar_name)) { log_error ("%s:%s: Failed to add attachment: %s", SRCNAME, __func__, att->get_display_name().c_str()); @@ -682,9 +689,16 @@ add_attachments_o(LPDISPATCH mail, xfree (wchar_file); xfree (wchar_name); - err = fixup_last_attachment_o (mail, att); + if (!err) + { + err = fixup_last_attachment_o (mail, att); + } + if (err) + { + anyError = true; + } } - return err; + return anyError; } GPGRT_LOCK_DEFINE(parser_lock); commit df2699ee2678466fbf5799a385f9a9c8d9bb66ee Author: Andre Heinecke Date: Wed Jul 11 08:31:54 2018 +0200 Log w32 error and tried filename for tmp attach * src/common.cpp (get_tmp_outfile): Log error and tried filename. -- This will help analyse issues like: GnuPG-Bug-Id: T4063 diff --git a/src/common.cpp b/src/common.cpp index 629690d..feb68ff 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -405,10 +405,6 @@ get_tmp_outfile (wchar_t *name, HANDLE *outHandle) return NULL; } - /* We should probably use the unicode variants here - but this would mean adding OpenStreamOnFileW to - out mapi */ - if (!GetTempPathW (MAX_PATH, tmpPath)) { log_error ("%s:%s: Could not get tmp path.", @@ -429,6 +425,8 @@ get_tmp_outfile (wchar_t *name, HANDLE *outHandle) FILE_ATTRIBUTE_TEMPORARY, NULL)) == INVALID_HANDLE_VALUE) { + log_debug_w32 (-1, "%s:%s: Failed to open candidate %S.", + SRCNAME, __func__, outName); wchar_t fnameBuf[MAX_PATH + 1]; wchar_t origName[MAX_PATH + 1]; memset (fnameBuf, 0, MAX_PATH + 1); ----------------------------------------------------------------------- Summary of changes: src/common.cpp | 6 ++---- src/mail.cpp | 24 +++++++++++++++++++----- 2 files changed, 21 insertions(+), 9 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 11 16:20:53 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Wed, 11 Jul 2018 16:20:53 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-89-g6cc842c Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 6cc842c9aa76d19448141e5117ac59452d7a1ff3 (commit) from 0e760e396fbf13e902d0dc0c048bff0d5410fa16 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 6cc842c9aa76d19448141e5117ac59452d7a1ff3 Author: Andre Heinecke Date: Wed Jul 11 16:18:24 2018 +0200 json: Add with-sec-fprs param to export * src/gpgme-json.c (add_secret_fprs): New helper. (op_export, hlp_export): Extend for with-sec fprs. -- This is a request from Mailvelope, to import an export they need the information for which keys from the export a secret key is also available. For simplicity it is much preferred to get this information in a single call without the need to do and parse a keylisting additionally in a second native-messaging call. So we make it optional to include that info in the export. diff --git a/src/gpgme-json.c b/src/gpgme-json.c index 1604d2f..ecdcc08 100644 --- a/src/gpgme-json.c +++ b/src/gpgme-json.c @@ -720,6 +720,54 @@ create_keylist_patterns (cjson_t request, const char *name) } +/* Do a secret keylisting for protocol proto and add the fingerprints of + the secret keys for patterns to the result as "sec-fprs" array. */ +static gpg_error_t +add_secret_fprs (const char **patterns, gpgme_protocol_t protocol, + cjson_t result) +{ + gpgme_ctx_t ctx; + gpg_error_t err; + gpgme_key_t key = NULL; + cjson_t j_fprs = xjson_CreateArray (); + + ctx = create_onetime_context (protocol); + + gpgme_set_keylist_mode (ctx, GPGME_KEYLIST_MODE_LOCAL | + GPGME_KEYLIST_MODE_WITH_SECRET); + + err = gpgme_op_keylist_ext_start (ctx, patterns, 1, 0); + + if (err) + { + gpg_error_object (result, err, "Error listing keys: %s", + gpg_strerror (err)); + goto leave; + } + + while (!(err = gpgme_op_keylist_next (ctx, &key))) + { + if (!key || !key->fpr) + continue; + cJSON_AddItemToArray (j_fprs, cJSON_CreateString (key->fpr)); + gpgme_key_unref (key); + key = NULL; + } + err = 0; + + release_onetime_context (ctx); + ctx = NULL; + + xjson_AddItemToObject (result, "sec-fprs", j_fprs); + +leave: + release_onetime_context (ctx); + gpgme_key_unref (key); + + return err; +} + + /* Create sigsum json array */ static cjson_t sigsum_to_json (gpgme_sigsum_t summary) @@ -2438,13 +2486,17 @@ static const char hlp_export[] = "minimal: Add EXPORT_MODE_MINIMAL.\n" "raw: Add EXPORT_MODE_RAW.\n" "pkcs12: Add EXPORT_MODE_PKCS12.\n" + "with-sec-fprs: Add the sec-fprs array to the result.\n" "\n" "Response on success:\n" - "type: \"keys\"\n" - "data: Unless armor mode is used a Base64 encoded binary.\n" - " In armor mode a string with an armored\n" - " OpenPGP or a PEM / PKCS12 key.\n" - "base64: Boolean indicating whether data is base64 encoded.\n"; + "type: \"keys\"\n" + "data: Unless armor mode is used a Base64 encoded binary.\n" + " In armor mode a string with an armored\n" + " OpenPGP or a PEM / PKCS12 key.\n" + "base64: Boolean indicating whether data is base64 encoded.\n" + "sec-fprs: Optional, only if with-secret is set. An array containing\n" + " the fingerprints of the keys in the export for which a secret\n" + " key is available"; static gpg_error_t op_export (cjson_t request, cjson_t result) { @@ -2453,6 +2505,7 @@ op_export (cjson_t request, cjson_t result) gpgme_protocol_t protocol; char **patterns = NULL; int abool; + int with_secret = 0; gpgme_export_mode_t mode = 0; gpgme_data_t output = NULL; @@ -2493,6 +2546,11 @@ op_export (cjson_t request, cjson_t result) if (abool) mode |= GPGME_EXPORT_MODE_PKCS12; + if ((err = get_boolean_flag (request, "with-sec-fprs", 0, &abool))) + goto leave; + if (abool) + with_secret = 1; + /* Get the export patterns. */ patterns = create_keylist_patterns (request, "keys"); @@ -2519,6 +2577,11 @@ op_export (cjson_t request, cjson_t result) "keys", !gpgme_get_armor (ctx)); output = NULL; + if (!err && with_secret) + { + err = add_secret_fprs ((const char **) patterns, protocol, result); + } + leave: xfree_array (patterns); release_context (ctx); ----------------------------------------------------------------------- Summary of changes: src/gpgme-json.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 5 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 12 09:28:48 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 12 Jul 2018 09:28:48 +0200 Subject: [git] GPG-ERROR - branch, master, updated. libgpg-error-1.31-12-gbd5bcd2 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Error codes used by GnuPG et al.". The branch, master has been updated via bd5bcd2dd19ef0b1c3d33a3a388b537ba08a4eb6 (commit) from 0727c394562237d7e626849eae04790264e56208 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit bd5bcd2dd19ef0b1c3d33a3a388b537ba08a4eb6 Author: Werner Koch Date: Thu Jul 12 09:17:52 2018 +0200 estream: Always propagate flush event to cookie functions. * src/estream.c (flush_stream): Always call cookie's flush func. Signed-off-by: Werner Koch diff --git a/src/estream.c b/src/estream.c index a1cc62e..8ad664e 100644 --- a/src/estream.c +++ b/src/estream.c @@ -1930,14 +1930,15 @@ flush_stream (estream_t stream) stream->intern->offset += stream->data_offset; stream->data_offset = 0; stream->data_flushed = 0; - - /* Propagate flush event. */ - (*func_write) (stream->intern->cookie, NULL, 0); } } else err = 0; + /* Always propagate flush event in case gpgrt_fflush was called + * explictly to do flush buffers in caller's cookie functions. */ + (*func_write) (stream->intern->cookie, NULL, 0); + out: if (err && errno != EAGAIN) ----------------------------------------------------------------------- Summary of changes: src/estream.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) hooks/post-receive -- Error codes used by GnuPG et al. http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 12 10:09:41 2018 From: cvs at cvs.gnupg.org (by NIIBE Yutaka) Date: Thu, 12 Jul 2018 10:09:41 +0200 Subject: [git] GnuPG - branch, gniibe/decryption-key, updated. gnupg-2.2.7-185-ge8caa28 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, gniibe/decryption-key has been updated via e8caa282d3d5f286919a1ed3db6699c555b7e89d (commit) via 76989d5bd89ed11f5b3656dc4748fcfc939a46dc (commit) via c2fd65ec8498a08ee36ca52d99b6b014f6db8d93 (commit) via 6c3567196f7e72552f326ce07dccbcce31926e5d (commit) via 135e46ea480d749b8a9692f71d4d0bfdadd8ee2f (commit) via cb71573f376235036c98143155e964a15cfcb250 (commit) via f7526c7bc754acf68bde0b79c785e875a9365d60 (commit) via 9ea9b9db7e1b3e6a84104a2be48d492f12c6316c (commit) via 01cd66f9faf1623833e6afac84164de5a136ecff (commit) via 60e7e102a153a246d7e887a64e30dbb4c4f7b6dd (commit) via 214b0077264e35c079e854a8b6374704aea45cd5 (commit) via 996febbab21eb9283b0634e51303a36b318734a6 (commit) via 8a915cd9faf052b4faa3c415f2ac5aa8d6ea1efe (commit) via 58baf40af641f8cbf597e508a292e85ae94688f1 (commit) via 3978df943dc7a4781a23382be2d3b4a96a04f71f (commit) via 1aacd12471935a354cfd85ee1805edc7eb16e6c5 (commit) via 592deeddb9bf4ae9b3e236b439e2f39644eb6d46 (commit) via b7cd2c2093ae1b47645be50fa1d431a028187cad (commit) via 386b9c4f25b28fd769d7563f2d86ac3a19cc3011 (commit) via 7e9aa307f76cdf2f624d43a35a8266e8b4e473f9 (commit) via 861f1da0731bf29dcb9221c4f22c76b40ec15a78 (commit) via 08147f8bbdca40c98c2a094fa48fab15b8339c80 (commit) via a4a054bf14fa855715faee01a152755c4e2a74f7 (commit) via bcdbf8b8ebe9d61160e0b007dabe1b6462ffbc93 (commit) via 1c0b6681e4f322b88ac35d1f21c03d3cfc35fc23 (commit) via 3e6ad302eaf3a4a9f3e60379133b3dfdbe0e1b2d (commit) via 5b40338f12762cd74238c2d2b3101c33dd2d0ed3 (commit) via cb52eb76b3ba0269742c5322e10a2b5151dafaf2 (commit) via 440472663d608660343c54f09172c851f5127c9c (commit) via fe621cc64b13b00914633630f28b4b417892d629 (commit) via 8f99299a54a0ac09f9c90c1085b704db78973fda (commit) via 2ddfb5bef920919443309ece9fa2930282bbce85 (commit) via 615b9d1fb779f3d5593484aa1e023b0ddff459f0 (commit) via d2bc66f241a66cc95140cbb3a07555f6301290ed (commit) via 13f135c7a252cc46cff96e75968d92b6dc8dce1b (commit) via 26746fe65d14a00773473c2d0d271406a5105bca (commit) via 26bce2f01d2029ea2b8a8dbbe36118e3c83c5cba (commit) via 1bc6b5174248ba4d83d648ef6d6f4550540d1f20 (commit) via 7ffc1ac7dd95d4cc1897a4c36d5cd628741c12f2 (commit) via 70f26e4263364f4b521c7856c38ba7ee59e38445 (commit) via 344b548dc71657d0285d93f78f17a2663b5e586f (commit) via 257661d6ae0ca376df758c38fabab2316d10e3a9 (commit) from 92d3dc9e1933cb877fe61942a68a76dcc4aab759 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit e8caa282d3d5f286919a1ed3db6699c555b7e89d Merge: 92d3dc9 76989d5 Author: NIIBE Yutaka Date: Thu Jul 12 17:09:14 2018 +0900 Merge branch 'master' into gniibe/decryption-key ----------------------------------------------------------------------- Summary of changes: NEWS | 42 +- agent/agent.h | 5 +- agent/cache.c | 34 +- agent/command.c | 233 ++++++++- agent/gpg-agent.c | 14 +- common/Makefile.am | 2 +- common/init.c | 6 +- common/logging.c | 1121 ------------------------------------------ common/logging.h | 94 +--- common/name-value.h | 2 +- common/percent.c | 44 ++ common/t-percent.c | 51 +- common/util.h | 16 +- configure.ac | 30 +- dirmngr/dns-stuff.c | 2 + dirmngr/dns.c | 57 ++- doc/DETAILS | 23 +- doc/gpg.texi | 22 +- doc/scdaemon.texi | 2 +- doc/tools.texi | 2 +- g10/Makefile.am | 1 + g10/card-util.c | 1 + g10/export.c | 19 +- g10/getkey.c | 49 +- g10/gpg.c | 17 +- g10/gpgcompose.c | 2 +- g10/gpgv.c | 15 + g10/import.c | 550 ++++++++++++++++----- g10/key-check.c | 241 +++++---- g10/{trust.c => key-clean.c} | 623 ++++++++--------------- g10/key-clean.h | 52 ++ g10/keydb.h | 38 ++ g10/keyedit.c | 1 + g10/keygen.c | 2 +- g10/keylist.c | 72 ++- g10/main.h | 3 + g10/mainproc.c | 27 +- g10/packet.h | 2 + g10/pkclist.c | 4 +- g10/sig-check.c | 17 +- g10/sign.c | 2 +- g10/test-stubs.c | 14 + g10/trust.c | 388 --------------- g10/trustdb.c | 1 + g10/trustdb.h | 41 -- po/Makevars | 58 ++- po/POTFILES.in | 1 - tools/send-mail.c | 2 +- tools/watchgnupg.c | 2 +- 49 files changed, 1650 insertions(+), 2397 deletions(-) delete mode 100644 common/logging.c copy g10/{trust.c => key-clean.c} (58%) create mode 100644 g10/key-clean.h hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 12 11:19:03 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 12 Jul 2018 11:19:03 +0200 Subject: [git] GPG-ERROR - branch, master, updated. libgpg-error-1.31-14-gaa24c16 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Error codes used by GnuPG et al.". The branch, master has been updated via aa24c16c46399cffbd33dffc822954d6f87be435 (commit) via 7b08307ff25b757ed2502cb2bf7893640e404ad1 (commit) from bd5bcd2dd19ef0b1c3d33a3a388b537ba08a4eb6 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit aa24c16c46399cffbd33dffc822954d6f87be435 Author: Werner Koch Date: Thu Jul 12 11:08:47 2018 +0200 Post release updates -- diff --git a/NEWS b/NEWS index d74210c..8c605b2 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ +Noteworthy changes in version 1.33 (unreleased) [C24/A24/R_] +----------------------------------------------- + + Noteworthy changes in version 1.32 (2018-07-12) [C24/A24/R3] ----------------------------------------------- diff --git a/configure.ac b/configure.ac index 2bcab34..b5c01ba 100644 --- a/configure.ac +++ b/configure.ac @@ -29,7 +29,7 @@ min_automake_version="1.14" # See below for the LT versions. m4_define([mym4_package],[libgpg-error]) m4_define([mym4_major], [1]) -m4_define([mym4_minor], [32]) +m4_define([mym4_minor], [33]) # Below is m4 magic to extract and compute the revision number, the # decimalized short revision number, a beta version string, and a flag diff --git a/po/es.po b/po/es.po index 8f18f3d..aaa27bf 100644 --- a/po/es.po +++ b/po/es.po @@ -8,12 +8,12 @@ msgstr "" "Project-Id-Version: libgpg-error 1.30-beta4\n" "Report-Msgid-Bugs-To: translations at gnupg.org\n" "PO-Revision-Date: 2018-04-15 08:52+0000\n" +"Last-Translator: Tails translators \n" "Language-Team: es \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Last-Translator: Tails translators \n" "X-Generator: Poedit 1.8.11\n" msgid "Unspecified source" diff --git a/po/uk.po b/po/uk.po index 37ec7d1..ff0ca16 100644 --- a/po/uk.po +++ b/po/uk.po @@ -941,11 +941,9 @@ msgstr "????? ??? ????? ? ????? ???????" msgid "Required environment variable not set" msgstr "?? ??????????? ????'??????? ??????? ??????????" -#| msgid "Already exists (LDAP)" msgid "User ID already exists" msgstr "????????????? ??????????? ??? ?????" -#| msgid "Already exists (LDAP)" msgid "Name already exists" msgstr "????? ??? ?????" commit 7b08307ff25b757ed2502cb2bf7893640e404ad1 Author: Werner Koch Date: Thu Jul 12 10:59:54 2018 +0200 Release 1.32 Signed-off-by: Werner Koch diff --git a/NEWS b/NEWS index b604db9..d74210c 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,14 @@ -Noteworthy changes in version 1.32 (unreleased) [C24/A24/R_] +Noteworthy changes in version 1.32 (2018-07-12) [C24/A24/R3] ----------------------------------------------- + * Fixes a problem with gpgrt_fflush and gpgrt_fopencookie. [#4069] + + * Fixes a problem with the C11 header stdnoreturn.h. [#4002] + + * The yat2m tool can now also be build on Windows. + + * Updates translations for Spanish, Russian and Ukrainian. + Noteworthy changes in version 1.31 (2018-05-02) [C24/A24/R2] ----------------------------------------------- diff --git a/README b/README index bab9c95..e0b9f16 100644 --- a/README +++ b/README @@ -24,7 +24,7 @@ components are - Option parser - - BAse-64 encoder and decoder. + - Base-64 encoder and decoder. More components will be added over time. Most functions are prefixed with "gpgrt" (GnuPG Run Time) instead of "gpg_err" to indicate the diff --git a/configure.ac b/configure.ac index 129cb61..2bcab34 100644 --- a/configure.ac +++ b/configure.ac @@ -51,7 +51,7 @@ AC_INIT([mym4_package],[mym4_version], [https://bugs.gnupg.org]) # Note that added error codes don't constitute an interface change. LIBGPG_ERROR_LT_CURRENT=24 LIBGPG_ERROR_LT_AGE=24 -LIBGPG_ERROR_LT_REVISION=2 +LIBGPG_ERROR_LT_REVISION=3 ################################################ AC_SUBST(LIBGPG_ERROR_LT_CURRENT) diff --git a/m4/Makefile.am b/m4/Makefile.am index b7b1963..a82737d 100644 --- a/m4/Makefile.am +++ b/m4/Makefile.am @@ -1,3 +1,5 @@ -EXTRA_DIST = inttypes-h.m4 lock.m4 visibility.m4 glibc2.m4 intmax.m4 longdouble.m4 longlong.m4 printf-posix.m4 signed.m4 size_max.m4 wchar_t.m4 wint_t.m4 xsize.m4 ac_prog_cc_for_build.m4 nls.m4 po.m4 codeset.m4 gettext.m4 glibc21.m4 iconv.m4 intdiv0.m4 inttypes.m4 inttypes_h.m4 inttypes-pri.m4 isc-posix.m4 lcmessage.m4 lib-ld.m4 lib-link.m4 lib-prefix.m4 progtest.m4 stdint_h.m4 uintmax_t.m4 ulonglong.m4 +EXTRA_DIST = inttypes-h.m4 lock.m4 visibility.m4 glibc2.m4 intmax.m4 longdouble.m4 longlong.m4 printf-posix.m4 signed.m4 size_max.m4 wchar_t.m4 wint_t.m4 xsize.m4 nls.m4 po.m4 codeset.m4 gettext.m4 glibc21.m4 iconv.m4 intdiv0.m4 inttypes.m4 inttypes_h.m4 inttypes-pri.m4 isc-posix.m4 lcmessage.m4 lib-ld.m4 lib-link.m4 lib-prefix.m4 progtest.m4 stdint_h.m4 uintmax_t.m4 ulonglong.m4 + +EXTRA_DIST += ax_cc_for_build.m4 EXTRA_DIST += autobuild.m4 estream.m4 readline.m4 gnupg-misc.m4 ----------------------------------------------------------------------- Summary of changes: NEWS | 14 +++++++++++++- README | 2 +- configure.ac | 4 ++-- m4/Makefile.am | 4 +++- po/es.po | 2 +- po/uk.po | 2 -- 6 files changed, 20 insertions(+), 8 deletions(-) hooks/post-receive -- Error codes used by GnuPG et al. http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 12 11:23:10 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 12 Jul 2018 11:23:10 +0200 Subject: [git] gnupg-doc - branch, master, updated. d7e8bb5ab2c4e35a881a3a503d8425ee15cef592 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GnuPG website and other docs". The branch, master has been updated via d7e8bb5ab2c4e35a881a3a503d8425ee15cef592 (commit) via f7aa0d8a14b9cfbda80cd8701872aef592bd286e (commit) from af6ff7f8443eb3353c77a6bdb2677eddbb0781fc (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit d7e8bb5ab2c4e35a881a3a503d8425ee15cef592 Author: Werner Koch Date: Thu Jul 12 11:13:58 2018 +0200 swdb: Release gpgrt 1.32 diff --git a/web/swdb.mac b/web/swdb.mac index 2765631..cc4a313 100644 --- a/web/swdb.mac +++ b/web/swdb.mac @@ -126,16 +126,16 @@ # # LIBGPG-ERROR # -#+macro: libgpg_error_ver 1.31 -#+macro: libgpg_error_date 2018-05-02 -#+macro: libgpg_error_size 880k -#+macro: libgpg_error_sha1 2bafad316d4e3e12bae4822b14ed9020090e6acf -#+macro: libgpg_error_sha2 40d0a823c9329478063903192a1f82496083b277265904878f4bc09e0db7a4ef -#+macro: gpgrt_ver 1.31 -#+macro: gpgrt_date 2018-05-02 -#+macro: gpgrt_size 880k -#+macro: gpgrt_sha1 2bafad316d4e3e12bae4822b14ed9020090e6acf -#+macro: gpgrt_sha2 40d0a823c9329478063903192a1f82496083b277265904878f4bc09e0db7a4ef +#+macro: libgpg_error_ver 1.32 +#+macro: libgpg_error_date 2018-07-12 +#+macro: libgpg_error_size 883k +#+macro: libgpg_error_sha1 e310718c7737c816cb1313a2f3baf60fd6a6d5d3 +#+macro: libgpg_error_sha2 c345c5e73cc2332f8d50db84a2280abfb1d8f6d4f1858b9daa30404db44540ca +#+macro: gpgrt_error_ver 1.32 +#+macro: gpgrt_error_date 2018-07-12 +#+macro: gpgrt_error_size 883k +#+macro: gpgrt_error_sha1 e310718c7737c816cb1313a2f3baf60fd6a6d5d3 +#+macro: gpgrt_error_sha2 c345c5e73cc2332f8d50db84a2280abfb1d8f6d4f1858b9daa30404db44540ca # commit f7aa0d8a14b9cfbda80cd8701872aef592bd286e Author: Werner Koch Date: Thu Jul 12 11:13:33 2018 +0200 drafts,openpgp-webkey-service: Add a security suggestion. diff --git a/misc/id/openpgp-webkey-service/draft.org b/misc/id/openpgp-webkey-service/draft.org index 3b4f717..f000e82 100644 --- a/misc/id/openpgp-webkey-service/draft.org +++ b/misc/id/openpgp-webkey-service/draft.org @@ -491,6 +491,12 @@ To make it a bit harder to test for published keys, the server responsible to serve the WELLKNOWN directory SHOULD NOT create an index file for that directory or any sub-directory. +The mail provider MUST make sure to filter a key in a way that only +the User ID belonging to that user is returned and that confirmation +requests are only send for such User IDs. It is further recommended +that a client filters the key for a publication requests so that only +a key with the specific User ID of the provider is send. + * IANA Considerations ----------------------------------------------------------------------- Summary of changes: misc/id/openpgp-webkey-service/draft.org | 6 ++++++ web/swdb.mac | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 10 deletions(-) hooks/post-receive -- The GnuPG website and other docs http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 12 11:42:11 2018 From: cvs at cvs.gnupg.org (by Maximilian Krambach) Date: Thu, 12 Jul 2018 11:42:11 +0200 Subject: [git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-73-g30bb549 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, javascript-binding has been updated via 30bb5490466119b66eeac255d71fb7bdc79149fa (commit) from 4015f5b4983c8a4590aa71776880d8bc42c7918d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 30bb5490466119b66eeac255d71fb7bdc79149fa Author: Maximilian Krambach Date: Thu Jul 12 11:36:55 2018 +0200 js: add with-sec-fprs to getKeysArmored -- * Reflects the changes made to gpgme-json in commit 6cc842c9aa76d19448141e5117ac59452d7a1ff3. - getKeysArmored now returns an object with property 'armored' being the exported armored block, and an (optional) array of fingerprint strings for those keys that can be used in sign/encrypt operations as property 'secret_fprs'. With this, extensions such as mailvelope will be able to bulk fetch all necessary key information in one request. diff --git a/lang/js/BrowserTestExtension/tests/KeyImportExport.js b/lang/js/BrowserTestExtension/tests/KeyImportExport.js index 33e6bd2..4a53c7a 100644 --- a/lang/js/BrowserTestExtension/tests/KeyImportExport.js +++ b/lang/js/BrowserTestExtension/tests/KeyImportExport.js @@ -22,7 +22,7 @@ * Raimund Renkert */ -/* global describe, it, expect, Gpgmejs, ImportablePublicKey */ +/* global describe, it, expect, Gpgmejs, ImportablePublicKey, inputvalues */ describe('Key importing', function () { it('Prepare test Key (deleting it from gnupg, if present)', function(done){ @@ -83,5 +83,30 @@ describe('Key importing', function () { }); }); }); - + it('exporting armored Key with getKeysArmored', function (done) { + let prm = Gpgmejs.init(); + const fpr = inputvalues.encrypt.good.fingerprint; + prm.then(function (context) { + context.Keyring.getKeysArmored(fpr).then(function(result){ + expect(result).to.be.an('object'); + expect(result.armored).to.be.a('string'); + expect(result.secret_fprs).to.be.undefined; + done(); + }); + }); + }); + it('exporting armored Key (including secret fingerprints) with ' + + 'getKeysArmored', function (done) { + let prm = Gpgmejs.init(); + const fpr = inputvalues.encrypt.good.fingerprint; + prm.then(function (context) { + context.Keyring.getKeysArmored(fpr, true).then(function(result){ + expect(result).to.be.an('object'); + expect(result.armored).to.be.a('string'); + expect(result.secret_fprs).to.be.an('array'); + expect(result.secret_fprs[0]).to.equal(fpr); + done(); + }); + }); + }); }); \ No newline at end of file diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index a0bdfcb..7a33be9 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -108,25 +108,45 @@ export class GPGME_Keyring { } /** + * @typedef {Object} exportResult The result of a getKeysArmored operation. + * @property {String} armored The public Key(s) as armored block. Note that + * the result is one armored block, and not a block per key. + * @property {Array} secret_fprs (optional) list of fingerprints + * for those Keys that also have a secret Key available in gnupg. The + * secret key will not be exported, but the fingerprint can be used in + * operations needing a secret key. + */ + + /** * Fetches the armored public Key blocks for all Keys matching the pattern - * (if no pattern is given, fetches all keys known to gnupg). Note that the - * result may be one big armored block, instead of several smaller armored - * blocks + * (if no pattern is given, fetches all keys known to gnupg). * @param {String|Array} pattern (optional) The Pattern to search * for - * @returns {Promise} Armored Key blocks + * @param {Boolean} with_secret_fpr (optional) also return a list of + * fingerprints for the keys that have a secret key available + * @returns {Promise} Object containing the + * armored Key(s) and additional information. * @static * @async */ - getKeysArmored(pattern) { + getKeysArmored(pattern, with_secret_fpr) { return new Promise(function(resolve, reject) { let msg = createMessage('export'); msg.setParameter('armor', true); + if (with_secret_fpr === true) { + msg.setParameter('with-sec-fprs', true); + } if (pattern !== undefined){ msg.setParameter('keys', pattern); } - msg.post().then(function(result){ - resolve(result.data); + msg.post().then(function(answer){ + const result = {armored: answer.data}; + if (with_secret_fpr === true + && answer.hasOwnProperty('sec-fprs') + ) { + result.secret_fprs = answer['sec-fprs']; + } + resolve(result); }, function(error){ reject(error); }); diff --git a/lang/js/src/permittedOperations.js b/lang/js/src/permittedOperations.js index 0b9c891..b5e9157 100644 --- a/lang/js/src/permittedOperations.js +++ b/lang/js/src/permittedOperations.js @@ -246,7 +246,10 @@ export const permittedOperations = { 'raw': { allowed: ['boolean'] }, - 'pkcs12':{ + 'pkcs12': { + allowed: ['boolean'] + }, + 'with-sec-fprs': { allowed: ['boolean'] } // secret: not yet implemented @@ -255,7 +258,8 @@ export const permittedOperations = { type: ['keys'], data: { 'data': 'string', - 'base64': 'boolean' + 'base64': 'boolean', + 'sec-fprs': 'object' } } }, @@ -295,10 +299,6 @@ export const permittedOperations = { allowed: ['string'], allowed_data: ['cms', 'openpgp'] }, - // 'secret': { not implemented - // allowed: ['boolean'] - // } - }, answer: { data: { ----------------------------------------------------------------------- Summary of changes: .../BrowserTestExtension/tests/KeyImportExport.js | 29 ++++++++++++++++-- lang/js/src/Keyring.js | 34 +++++++++++++++++----- lang/js/src/permittedOperations.js | 12 ++++---- 3 files changed, 60 insertions(+), 15 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 12 11:50:22 2018 From: cvs at cvs.gnupg.org (by Maximilian Krambach) Date: Thu, 12 Jul 2018 11:50:22 +0200 Subject: [git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-74-g5213a59 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, javascript-binding has been updated via 5213a599fea0da64560f935dffbf6b27a39d4850 (commit) from 30bb5490466119b66eeac255d71fb7bdc79149fa (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 5213a599fea0da64560f935dffbf6b27a39d4850 Author: Maximilian Krambach Date: Thu Jul 12 11:48:17 2018 +0200 js: allow optional Key retrieve pattern to be null -- * src/Keyring.js: If the optional "pattern" parameter is not to be used, but another, following parameter is, null is more of a convention in javascript, thus both null and undefined are interpreted as "this parameter is not meant to be set". diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index 7a33be9..cefc812 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -53,7 +53,7 @@ export class GPGME_Keyring { getKeys(pattern, prepare_sync=false, search=false){ return new Promise(function(resolve, reject) { let msg = createMessage('keylist'); - if (pattern !== undefined){ + if (pattern !== undefined && pattern !== null){ msg.setParameter('keys', pattern); } msg.setParameter('sigs', true); @@ -136,7 +136,7 @@ export class GPGME_Keyring { if (with_secret_fpr === true) { msg.setParameter('with-sec-fprs', true); } - if (pattern !== undefined){ + if (pattern !== undefined && pattern !== null){ msg.setParameter('keys', pattern); } msg.post().then(function(answer){ ----------------------------------------------------------------------- Summary of changes: lang/js/src/Keyring.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 12 16:43:48 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 12 Jul 2018 16:43:48 +0200 Subject: [git] gnupg-doc - branch, master, updated. 04099d73f1ba48fe7e947e2f6633c289772aeb1e Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GnuPG website and other docs". The branch, master has been updated via 04099d73f1ba48fe7e947e2f6633c289772aeb1e (commit) from d7e8bb5ab2c4e35a881a3a503d8425ee15cef592 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 04099d73f1ba48fe7e947e2f6633c289772aeb1e Author: Werner Koch Date: Thu Jul 12 16:35:09 2018 +0200 swdb: Release gnupg 2.2.9 diff --git a/web/swdb.mac b/web/swdb.mac index cc4a313..2ae727d 100644 --- a/web/swdb.mac +++ b/web/swdb.mac @@ -10,17 +10,17 @@ # # GnuPG-2.2 # -#+macro: gnupg22_ver 2.2.8 -#+macro: gnupg22_date 2018-06-08 -#+macro: gnupg22_size 6477k -#+macro: gnupg22_sha1 d87553a125832ea90e8aeb3ceeecf24f88de56fb -#+macro: gnupg22_sha2 777b4cb8ced21965a5053d4fa20fe11484f0a478f3d011cef508a1a49db50dcd +#+macro: gnupg22_ver 2.2.9 +#+macro: gnupg22_date 2018-07-12 +#+macro: gnupg22_size 6503k +#+macro: gnupg22_sha1 e6ef18c2e06175bbe563959c9acc682c02bcd572 +#+macro: gnupg22_sha2 6278eaabffa1ebc9fa2ceb3dc53eea9a1505ab02a668a86dd6fec06951af2164 #+macro: gnupg22_branch STABLE-BRANCH-2-2 -#+macro: gnupg22_w32_ver 2.2.8_20180613 -#+macro: gnupg22_w32_date 2018-06-13 -#+macro: gnupg22_w32_size 3915k -#+macro: gnupg22_w32_sha1 c91b0132319e2b9811901e453f6cb20c06cd73e2 -#+macro: gnupg22_w32_sha2 6d2b9269cc808d3dceffe3d7f368738402e7faed49cd823799bcfbdaedc57d3f +#+macro: gnupg22_w32_ver 2.2.9_20180712 +#+macro: gnupg22_w32_date 2018-07-12 +#+macro: gnupg22_w32_size 3922k +#+macro: gnupg22_w32_sha1 a0c234781d85d5ef530636622f3d6d80a8d46b5e +#+macro: gnupg22_w32_sha2 1b8b9fad41c1beb92549ff8ee33530ae589514b1f0addbbdba95554fe6d5ccb3 # ----------------------------------------------------------------------- Summary of changes: web/swdb.mac | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) hooks/post-receive -- The GnuPG website and other docs http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 12 20:57:41 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 12 Jul 2018 20:57:41 +0200 Subject: [git] gnupg-doc - branch, master, updated. d07083d48699894dbbde5152a3d55a005ee728da Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GnuPG website and other docs". The branch, master has been updated via d07083d48699894dbbde5152a3d55a005ee728da (commit) from 04099d73f1ba48fe7e947e2f6633c289772aeb1e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit d07083d48699894dbbde5152a3d55a005ee728da Author: Werner Koch Date: Thu Jul 12 20:49:21 2018 +0200 web: Release annoucement for 2.2.9 diff --git a/web/index.org b/web/index.org index 1e82ba3..aff93ea 100644 --- a/web/index.org +++ b/web/index.org @@ -65,6 +65,11 @@ The latest release news:\\ # GnuPG's latest news are available as [[http://feedvalidator.org/check.cgi?url%3Dhttps://www.gnupg.org/news.en.rss][RSS 2.0 compliant]] feed. Just # point or paste the [[news.en.rss][RSS file]] into your aggregator. +** GnuPG 2.2.9 released (2018-07-12) + +We are pleased to announce the availability of GnuPG version 2.2.9. +This is a maintenance release fixing a few problems. {[[https://lists.gnupg.org/pipermail/gnupg-announce/2018q3/000427.html][more]]} + ** Libgcrypt 1.8.3 released (2018-06-13) We are pleased to announce the availability of [[file:software/libgcrypt/index.org][Libgcrypt]] version 1.8.3 ----------------------------------------------------------------------- Summary of changes: web/index.org | 5 +++++ 1 file changed, 5 insertions(+) hooks/post-receive -- The GnuPG website and other docs http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 12 21:00:07 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 12 Jul 2018 21:00:07 +0200 Subject: [git] GnuPG - branch, master, updated. gnupg-2.2.7-178-g011ab7e Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 011ab7ec6615be741d98cf855e7c6ee40effdb32 (commit) from 76989d5bd89ed11f5b3656dc4748fcfc939a46dc (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 011ab7ec6615be741d98cf855e7c6ee40effdb32 Author: Werner Koch Date: Thu Jul 12 20:51:02 2018 +0200 doc: Add NEWS about the 2.2.9 release -- diff --git a/NEWS b/NEWS index 232d8be..27f78b1 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,46 @@ Noteworthy changes in version 2.3.0 (unreleased) ------------------------------------------------ + Changes also found in 2.2.9: + + * dirmngr: Fix recursive resolver mode and other bugs in the libdns + code. [#3374,#3803,#3610] + + * dirmngr: When using libgpg-error 1.32 or later a GnuPG build with + NTBTLS support (e.g. the standard Windows installer) does not + anymore block for dozens of seconds before returning data. + + * gpg: Fix bug in --show-keys which actually imported revocation + certificates. [#4017] + + * gpg: Ignore too long user-ID and comment packets. [#4022] + + * gpg: Fix crash due to bad German translation. Improved printf + format compile time check. + + * gpg: Handle missing ISSUER sub packet gracefully in the presence of + the new ISSUER_FPR. [#4046] + + * gpg: Allow decryption using several passphrases in most cases. + [#3795,#4050] + + * gpg: Command --show-keys now enables the list options + show-unusable-uids, show-unusable-subkeys, show-notations and + show-policy-urls by default. + + * gpg: Command --show-keys now prints revocation certificates. [#4018] + + * gpg: Add revocation reason to the "rev" and "rvs" records of the + option --with-colons. [#1173] + + * gpg: Export option export-clean does now remove certain expired + subkeys; export-minimal removes all expired subkeys. [#3622] + + * gpg: New "usage" property for the drop-subkey filters. [#4019] + + Release-info: https://dev.gnupg.org/T4036 + See-also: gnupg-announce/2018q3/000427.html + Changes also found in 2.2.8: * gpg: Decryption of messages not using the MDC mode will now lead @@ -285,6 +325,7 @@ Noteworthy changes in version 2.3.0 (unreleased) Version 2.2.6 (2018-04-09) Version 2.2.7 (2018-05-02) Version 2.2.8 (2018-06-08) + Version 2.2.9 (2018-07-12) Noteworthy changes in version 2.2.0 (2017-08-28) ----------------------------------------------------------------------- Summary of changes: NEWS | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Fri Jul 13 12:39:08 2018 From: cvs at cvs.gnupg.org (by Ben McGinnes) Date: Fri, 13 Jul 2018 12:39:08 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-90-g1bb3f84 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 1bb3f8409d4bbec403bea768184a691d9d7ea42d (commit) from 6cc842c9aa76d19448141e5117ac59452d7a1ff3 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 1bb3f8409d4bbec403bea768184a691d9d7ea42d Author: Ben McGinnes Date: Fri Jul 13 20:36:27 2018 +1000 python bindings: example scripts * Fixed incorrect mention of output prompt referencing secret keys when the scripts are only for exporting public keys in whole or minimised forms. diff --git a/lang/python/examples/howto/export-key.py b/lang/python/examples/howto/export-key.py index 6def687..913bfce 100755 --- a/lang/python/examples/howto/export-key.py +++ b/lang/python/examples/howto/export-key.py @@ -47,7 +47,7 @@ elif len(sys.argv) == 2: logrus = input("Enter the UID matching the key(s) to export: ") homedir = input("Enter the GPG configuration directory path (optional): ") else: - keyfile = input("Enter the path and filename to save the secret key to: ") + keyfile = input("Enter the path and filename to save the key(s) to: ") logrus = input("Enter the UID matching the key(s) to export: ") homedir = input("Enter the GPG configuration directory path (optional): ") diff --git a/lang/python/examples/howto/export-minimised-key.py b/lang/python/examples/howto/export-minimised-key.py index c2c533e..3889adc 100755 --- a/lang/python/examples/howto/export-minimised-key.py +++ b/lang/python/examples/howto/export-minimised-key.py @@ -47,7 +47,7 @@ elif len(sys.argv) == 2: logrus = input("Enter the UID matching the key(s) to export: ") homedir = input("Enter the GPG configuration directory path (optional): ") else: - keyfile = input("Enter the path and filename to save the secret key to: ") + keyfile = input("Enter the path and filename to save the key(s) to: ") logrus = input("Enter the UID matching the key(s) to export: ") homedir = input("Enter the GPG configuration directory path (optional): ") ----------------------------------------------------------------------- Summary of changes: lang/python/examples/howto/export-key.py | 2 +- lang/python/examples/howto/export-minimised-key.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Fri Jul 13 14:11:17 2018 From: cvs at cvs.gnupg.org (by Ben McGinnes) Date: Fri, 13 Jul 2018 14:11:17 +0200 Subject: [git] GPGME - branch, ben/howto-dita, updated. gpgme-1.11.1-17-g1e34141 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, ben/howto-dita has been updated via 1e34141f6770cd8ca243048ec6f78d600bed4262 (commit) from dda54cc851490be045832d5ee0b03be082529d17 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 1e34141f6770cd8ca243048ec6f78d600bed4262 Author: Ben McGinnes Date: Fri Jul 13 22:08:42 2018 +1000 python bindings howto: dita version * Numerous updates to bring it back into sync with the official doc. * Especially important since it now looks like the babel thing is a real bug after all and not me doing something stupid. diff --git a/lang/python/docs/dita/gpgme-python-howto.ditamap b/lang/python/docs/dita/gpgme-python-howto.ditamap index 1809acb..10ba8a6 100644 --- a/lang/python/docs/dita/gpgme-python-howto.ditamap +++ b/lang/python/docs/dita/gpgme-python-howto.ditamap @@ -39,7 +39,7 @@ - + diff --git a/lang/python/docs/dita/howto/part02/installing.dita b/lang/python/docs/dita/howto/part02/installing.dita index 879f6ca..4ede496 100644 --- a/lang/python/docs/dita/howto/part02/installing.dita +++ b/lang/python/docs/dita/howto/part02/installing.dita @@ -16,8 +16,8 @@

    For Python 2 it checks for these executables in this order: python, python2 and python2.7.

    For Python 3 it checks for these executables in this order: python3, - python3.6, python3.5 and - python3.4.

    + python3.6, python3.5, python3.4 + and python3.7.

    diff --git a/lang/python/docs/dita/howto/part02/daesh.dita b/lang/python/docs/dita/howto/part02/isis-gnupg.dita similarity index 100% rename from lang/python/docs/dita/howto/part02/daesh.dita rename to lang/python/docs/dita/howto/part02/isis-gnupg.dita diff --git a/lang/python/docs/dita/howto/part03/exporting-pubkeys.dita b/lang/python/docs/dita/howto/part03/exporting-pubkeys.dita index 8ae4f5b..f632eb6 100644 --- a/lang/python/docs/dita/howto/part03/exporting-pubkeys.dita +++ b/lang/python/docs/dita/howto/part03/exporting-pubkeys.dita @@ -5,9 +5,9 @@ Exporting Public Keys

    There are two methods of exporting public keys, both of which are very similar to the - other. The default method, key_export() will export a public key or keys + other. The default method, key_export(), will export a public key or keys matching a specified pattern as normal. The alternative, the - key_export_minimal() method will do the same thing except producing a + key_export_minimal() method, will do the same thing except producing a minimised output with extra signatures and third party signatures or certifications removed.

    diff --git a/lang/python/docs/dita/howto/part03/importing-eff-keys.dita b/lang/python/docs/dita/howto/part03/importing-eff-keys.dita new file mode 100644 index 0000000..124ebda --- /dev/null +++ b/lang/python/docs/dita/howto/part03/importing-eff-keys.dita @@ -0,0 +1,74 @@ + + + + + Importing Keys + DRAFT VERSION + +

    Importing keys is possible with the key_import() method and takes one + argument which is a bytes literal object containing either the binary or ASCII armoured key + data for one or more keys.

    +

    In the following example a key will be retrieved from the SKS keyservers via the web using + the requests module. Since requests returns the content as a bytes literal object, we can + then use that directly to import the resulting data into our keybox. In order to demonstrate + multiple imports this example searches for all the keys of users at a particular domain + name. This time we're using the EFF, since they've always been such good supporters of + strong encryption and good security practices.

    +

    If this holds true then I would expect that some keys I already have will be updated and + some others will be added. Most of the keys created most recently and belonging to still + active people within the EFF should, if they are following their own recent statements, be + revoked. If they are not revoked then it would be best left to the reader to determine + whether or not the change in leadership at that organisation indicates a change in their + policy of supporting good security practices.

    +

    + import gpg +import requests + +c = gpg.Context() +url = "https://sks-keyservers.net/pks/lookup" +pattern = input("Enter the pattern to search for key or user IDs: ") +payload = { "op": "get", "search": pattern } + +r = requests.get(url, verify=True, params=payload) +k = c.key_import(r.content) + +summary = """ +Total number of keys: {0} +Total number imported: {1} +Number of version 3 keys ignored: {2} + +Number of imported key objects or updates: {3} +Number of unchanged keys: {4} +Number of new signatures: {5} +Number of revoked keys: {6} +""".format(k.considered, len(k.imports), k.skipped_v3_keys, k.imported, + k.unchanged, k.new_signatures, k.new_revocations) + +print(summary) +

    +

    The resulting output in that case, where the search pattern entered was + @eff.org was:

    +

    + Total number of keys: 272 +Total number imported: 249 +Number of version 3 keys ignored: 23 + +Number of imported key objects or updates: 180 +Number of unchanged keys: 66 +Number of new signatures: 7 +Number of revoked keys: 0 +

    +

    The 23 skipped keys all date back to the 1990s, some of which were made very shortly after + PGP 2 was first released.

    +

    + Pretty Good Privacy version 2 and above are the only versions with any widespread use. + Pretty Good Privacy version 1 had a number of serious security problems, not least of + which being that it relied on an encryption algorithm called Bass-O-Matic which was + written by Phil Zimmermann. Following feedback on this algorithm, Zimmermann withdrew + version 1 and re-implemented version 2 using RSA and IDEA, even though both were subject + to software patents at the time (both of those software patents have long since + expired). +

    + + + diff --git a/lang/python/docs/dita/howto/version-info.dita b/lang/python/docs/dita/howto/version-info.dita index f9bb42a..f07c136 100644 --- a/lang/python/docs/dita/howto/version-info.dita +++ b/lang/python/docs/dita/howto/version-info.dita @@ -4,7 +4,7 @@ Documentation Version -

    Version: 0.1.2-DRAFT

    +

    Version: 0.1.3-DRAFT

    Author: Ben McGinnes <ben at gnupg.org>

    Author GPG Key ID: ----------------------------------------------------------------------- Summary of changes: lang/python/docs/dita/gpgme-python-howto.ditamap | 2 +- lang/python/docs/dita/howto/part02/installing.dita | 4 +- .../howto/part02/{daesh.dita => isis-gnupg.dita} | 0 .../docs/dita/howto/part03/exporting-pubkeys.dita | 4 +- .../docs/dita/howto/part03/importing-eff-keys.dita | 74 ++++++++++++++++++++++ lang/python/docs/dita/howto/version-info.dita | 2 +- 6 files changed, 80 insertions(+), 6 deletions(-) rename lang/python/docs/dita/howto/part02/{daesh.dita => isis-gnupg.dita} (100%) create mode 100644 lang/python/docs/dita/howto/part03/importing-eff-keys.dita hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 16 09:49:12 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Mon, 16 Jul 2018 09:49:12 +0200 Subject: [git] gnupg-doc - branch, master, updated. 69cdc11cda9b788c112a72269ceee5aa3d5149ae Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GnuPG website and other docs". The branch, master has been updated via 69cdc11cda9b788c112a72269ceee5aa3d5149ae (commit) from d07083d48699894dbbde5152a3d55a005ee728da (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 69cdc11cda9b788c112a72269ceee5aa3d5149ae Author: Werner Koch Date: Mon Jul 16 09:40:28 2018 +0200 swdb: Release npth 1.6 diff --git a/web/swdb.mac b/web/swdb.mac index 2ae727d..a6d755c 100644 --- a/web/swdb.mac +++ b/web/swdb.mac @@ -161,11 +161,11 @@ # # nPth # -#+macro: npth_ver 1.5 -#+macro: npth_date 2017-06-02 -#+macro: npth_size 292k -#+macro: npth_sha1 93ddf1a3bdbca00fb4cf811498094ca61bbb8ee1 -#+macro: npth_sha2 294a690c1f537b92ed829d867bee537e46be93fbd60b16c04630fbbfcd9db3c2 +#+macro: npth_ver 1.6 +#+macro: npth_date 2018-07-16 +#+macro: npth_size 293k +#+macro: npth_sha1 f9d63e9747b027e4e404fe3c20c73c73719e1731 +#+macro: npth_sha2 1393abd9adcf0762d34798dc34fdcf4d0d22a8410721e76f1e3afcd1daa4e2d1 # ----------------------------------------------------------------------- Summary of changes: web/swdb.mac | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) hooks/post-receive -- The GnuPG website and other docs http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 16 12:46:11 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Mon, 16 Jul 2018 12:46:11 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-91-g013a7f4 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 013a7f47ab486c380b3c97637d3b15f11de74fe8 (commit) from 1bb3f8409d4bbec403bea768184a691d9d7ea42d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 013a7f47ab486c380b3c97637d3b15f11de74fe8 Author: Werner Koch Date: Mon Jul 16 12:34:52 2018 +0200 json: Fix buffer overflow in cJSON.c * src/cJSON.c (parse_string): Correctly detect bad hex. -- The call to parse_hex4 checks that only hex digits follow and in the error case returns 0. However, by the time of the combined check for an invalid value and the error PTR has already been set to the last hex character and thus if the end-of-string or a quote character was one of the bad hex digits the loop will miss the end of the string which does not match with the simple buffer length allocation test at the begin of the function. Signed-off-by: Werner Koch diff --git a/src/cJSON.c b/src/cJSON.c index 38cb152..610ff92 100644 --- a/src/cJSON.c +++ b/src/cJSON.c @@ -275,17 +275,22 @@ parse_string (cJSON * item, const char *str, const char **ep) break; case 'u': /* transcode utf16 to utf8. */ uc = parse_hex4 (ptr + 1); + if (!uc) + break; /* Bad hex; continue right after the 'u'. */ ptr += 4; /* get the unicode char. */ - if ((uc >= 0xDC00 && uc <= 0xDFFF) || uc == 0) + if ((uc >= 0xDC00 && uc <= 0xDFFF)) break; /* check for invalid. */ if (uc >= 0xD800 && uc <= 0xDBFF) /* UTF16 surrogate pairs. */ { if (ptr[1] != '\\' || ptr[2] != 'u') break; /* missing second-half of surrogate. */ - uc2 = parse_hex4 (ptr + 3); - ptr += 6; + ptr += 2; + uc2 = parse_hex4 (ptr + 1); + if (!uc2) + break; /* Bad hex; continue right after the 'u'. */ + ptr += 4; if (uc2 < 0xDC00 || uc2 > 0xDFFF) break; /* invalid second-half of surrogate. */ uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF)); ----------------------------------------------------------------------- Summary of changes: src/cJSON.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 16 14:50:59 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Mon, 16 Jul 2018 14:50:59 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-92-g1933f5b Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 1933f5b8056b2671301379106cca4504c4187795 (commit) from 013a7f47ab486c380b3c97637d3b15f11de74fe8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 1933f5b8056b2671301379106cca4504c4187795 Author: Werner Koch Date: Mon Jul 16 14:42:30 2018 +0200 json: Minor cleanups in cJSON.c * src/cJSON.c: Add comments on the origin of the code. (parse_string): Allocate an extra byte for safeness. (cJSON_AddItemToArray): Allo ARRAY to be NULL. Signed-off-by: Werner Koch diff --git a/src/cJSON.c b/src/cJSON.c index 610ff92..65d105b 100644 --- a/src/cJSON.c +++ b/src/cJSON.c @@ -22,7 +22,14 @@ * SPDX-License-Identifier: MIT * * Note that this code has been modified from the original code taken - * from cjson-code-58.zip. + * from cjson-code-58.zip before 2014 (my first local commit was in + * 2014 but I may used the code even earlier). Since 2016 the project + * was revived and moved to https://github.com/DaveGamble/cJSON.git. + * It is now a lot more complex and has substantial changes so that it + * is not possible to merge them directly. In any case we only need a + * simple parser and not a complete library. I have looked through + * the commits and fixed a few things which should apply; I also added + * a few references to the upstream code. Regression test are missing! */ #ifdef HAVE_CONFIG_H @@ -232,6 +239,9 @@ parse_string (cJSON * item, const char *str, const char **ep) char *out; int len = 0; unsigned uc, uc2; + + /* FIXME: We should consider eary failure like it is done with + * commit 8656386c4f4a12f1cf3d6b26158407fd05e65029 in upstream. */ if (*str != '\"') { *ep = str; @@ -242,8 +252,10 @@ parse_string (cJSON * item, const char *str, const char **ep) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ - out = xtrymalloc (len + 1); /* This is how long we need for the - string, roughly. */ + out = xtrymalloc (len + 2); /* This is how long we need for the + * string, roughly. We add one extra + * byte in case the last input + * character is a backslash. */ if (!out) return 0; @@ -322,6 +334,8 @@ parse_string (cJSON * item, const char *str, const char **ep) ptr2 += len; break; default: + /* Fixme: Should we fail here: See + * https://github.com/DaveGamble/cJSON/issues/10 */ *ptr2++ = *ptr; break; } @@ -934,9 +948,11 @@ create_reference (cJSON * item) void cJSON_AddItemToArray (cJSON * array, cJSON * item) { - cJSON *c = array->child; - if (!item) + cJSON *c; + + if (!item || !array) return; + c = array->child; if (!c) { array->child = item; @@ -1137,6 +1153,8 @@ cJSON_ReplaceItemInObject (cJSON * object, const char *string, i++, c = c->next; if (c) { + /* FIXME: I guess we should free newitem->string here. See + * upstream commit 0d10e279c8b604f71829b5d49d092719f4ae96b6. */ newitem->string = xtrystrdup (string); cJSON_ReplaceItemInArray (object, i, newitem); } ----------------------------------------------------------------------- Summary of changes: src/cJSON.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 16 19:48:34 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Mon, 16 Jul 2018 19:48:34 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-94-g1686e07 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 1686e07e77a1eee3b2708d0231a5a549956021f7 (commit) via cc21101a7494ea0a17c3012fcb86e77b00b494fa (commit) from 1933f5b8056b2671301379106cca4504c4187795 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 1686e07e77a1eee3b2708d0231a5a549956021f7 Author: Andre Heinecke Date: Mon Jul 16 19:47:11 2018 +0200 json: Fix crash on invalid json * src/gpgme-json.c (process_request): Init res. Check for json object before encode and chunk. -- If json is invalid we can't read chunksize and would crash in encode and chunk. diff --git a/src/gpgme-json.c b/src/gpgme-json.c index 0aeb7f9..06f09ef 100644 --- a/src/gpgme-json.c +++ b/src/gpgme-json.c @@ -3104,7 +3104,7 @@ process_request (const char *request) int helpmode; int is_getmore = 0; const char *op; - char *res; + char *res = NULL; int idx; response = xjson_CreateObject (); @@ -3188,7 +3188,7 @@ process_request (const char *request) else res = cJSON_PrintUnformatted (response); } - else + else if (json) res = encode_and_chunk (json, response); if (!res) log_error ("Printing JSON data failed\n"); commit cc21101a7494ea0a17c3012fcb86e77b00b494fa Author: Andre Heinecke Date: Mon Jul 16 19:46:04 2018 +0200 json: Fix uninitialized key unref in op_delete * src/gpgme-json.c (op_delete): Init key. diff --git a/src/gpgme-json.c b/src/gpgme-json.c index ecdcc08..0aeb7f9 100644 --- a/src/gpgme-json.c +++ b/src/gpgme-json.c @@ -2607,7 +2607,7 @@ op_delete (cjson_t request, cjson_t result) gpgme_ctx_t ctx = NULL; gpgme_ctx_t keylist_ctx = NULL; gpgme_protocol_t protocol; - gpgme_key_t key; + gpgme_key_t key = NULL; int secret = 0; cjson_t j_key = NULL; ----------------------------------------------------------------------- Summary of changes: src/gpgme-json.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 17 07:15:30 2018 From: cvs at cvs.gnupg.org (by NIIBE Yutaka) Date: Tue, 17 Jul 2018 07:15:30 +0200 Subject: [git] GnuPG - branch, master, updated. gnupg-2.2.7-179-g1c9584d Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 1c9584dabb21b6ea5865316e6bad34576094921c (commit) from 011ab7ec6615be741d98cf855e7c6ee40effdb32 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 1c9584dabb21b6ea5865316e6bad34576094921c Author: NIIBE Yutaka Date: Tue Jul 17 14:14:39 2018 +0900 Register DCO fo Michael Haubenwallner. -- diff --git a/AUTHORS b/AUTHORS index f43208a..2251cf6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -205,6 +205,9 @@ Jussi Kivilinna Kyle Butt 2013-05-29:CAAODAYLbCtqOG6msLLL0UTdASKWT6u2ptxsgUQ1JpusBESBoNQ at mail.gmail.com: +Michael Haubenwallner +2018-07-13:c397e637-f1ce-34f0-7e6a-df04a76e1c35 at ssi-schaefer.com: + Phil Pennock Phil Pennock 2017-01-19:20170119061225.GA26207 at breadbox.private.spodhuis.org: ----------------------------------------------------------------------- Summary of changes: AUTHORS | 3 +++ 1 file changed, 3 insertions(+) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 17 07:21:41 2018 From: cvs at cvs.gnupg.org (by Michael Haubenwallner) Date: Tue, 17 Jul 2018 07:21:41 +0200 Subject: [git] GPG-ERROR - branch, master, updated. libgpg-error-1.32-2-g19f9902 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Error codes used by GnuPG et al.". The branch, master has been updated via 19f9902b004cb980de4da908fa571103bfe2b630 (commit) from aa24c16c46399cffbd33dffc822954d6f87be435 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 19f9902b004cb980de4da908fa571103bfe2b630 Author: Michael Haubenwallner Date: Thu Jul 12 17:36:13 2018 +0200 build: use EXEEXT_FOR_BUILD everywhere. * src/Makefile.am: Use EXEEXT_FOR_BUILD with all build tools. Signed-off-by: Michael Haubenwallner diff --git a/src/Makefile.am b/src/Makefile.am index 42998e4..fcfbb83 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -105,9 +105,9 @@ tmp_files = _mkerrcodes.h _gpg-error.def.h mkw32errmap.tab.h mkw32errmap.map.c CLEANFILES = err-sources.h err-codes.h code-to-errno.h code-from-errno.h \ gpg-error.h gpgrt.h gpgrt-config \ - mkerrcodes mkerrcodes.h gpg-error.def mkw32errmap.tab.h \ + mkerrcodes$(EXEEXT_FOR_BUILD) mkerrcodes.h gpg-error.def mkw32errmap.tab.h \ mkw32errmap.map.c err-sources-sym.h err-codes-sym.h errnos-sym.h \ - gpg-extra/errno.h mkheader $(tmp_files) lock-obj-pub.native.h + gpg-extra/errno.h mkheader$(EXEEXT_FOR_BUILD) $(tmp_files) lock-obj-pub.native.h # @@ -246,11 +246,11 @@ if HAVE_W32CE_SYSTEM mkw32errmap.tab.h: Makefile mkw32errmap.c $(CPP) -DRESOLVE_MACROS $(srcdir)/mkw32errmap.c | \ grep '{&mkw32errmap_marker' >$@ -mkw32errmap.map.c: mkw32errmap - ./mkw32errmap --map > $@ -gpg-extra/errno.h: mkw32errmap +mkw32errmap.map.c: mkw32errmap$(EXEEXT_FOR_BUILD) + ./mkw32errmap$(EXEEXT_FOR_BUILD) --map > $@ +gpg-extra/errno.h: mkw32errmap$(EXEEXT_FOR_BUILD) -$(MKDIR_P) gpg-extra - ./mkw32errmap > $@ + ./mkw32errmap$(EXEEXT_FOR_BUILD) > $@ else mkw32errmap.map.c: echo "/*dummy*/" > $@ @@ -266,18 +266,18 @@ gpg-error.def: Makefile gpg-error.def.in # It is correct to use $(CC_FOR_BUILD) here. We want to run the # program at build time. -mkerrcodes: mkerrcodes.c mkerrcodes.h Makefile +mkerrcodes$(EXEEXT_FOR_BUILD): mkerrcodes.c mkerrcodes.h Makefile $(CC_FOR_BUILD) -I. -I$(srcdir) -o $@ $(srcdir)/mkerrcodes.c if HAVE_W32CE_SYSTEM # It is correct to use $(CC_FOR_BUILD) here. We want to run the # program at build time. -mkw32errmap: mkw32errmap.c mkw32errmap.tab.h Makefile +mkw32errmap$(EXEEXT_FOR_BUILD): mkw32errmap.c mkw32errmap.tab.h Makefile $(CC_FOR_BUILD) -I. -I$(srcdir) -o $@ $(srcdir)/mkw32errmap.c endif -code-from-errno.h: mkerrcodes Makefile - ./mkerrcodes | $(AWK) -f $(srcdir)/mkerrcodes2.awk >$@ +code-from-errno.h: mkerrcodes$(EXEEXT_FOR_BUILD) Makefile + ./mkerrcodes$(EXEEXT_FOR_BUILD) | $(AWK) -f $(srcdir)/mkerrcodes2.awk >$@ errnos-sym.h: Makefile mkstrtable.awk errnos.in $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=2 -v nogettext=1 \ @@ -285,7 +285,7 @@ errnos-sym.h: Makefile mkstrtable.awk errnos.in $(srcdir)/errnos.in >$@ -mkheader: mkheader.c Makefile +mkheader$(EXEEXT_FOR_BUILD): mkheader.c Makefile $(CC_FOR_BUILD) -g -O0 -I. -I$(srcdir) -o $@ $(srcdir)/mkheader.c parts_of_gpg_error_h = \ @@ -312,10 +312,10 @@ endif # We also depend on versioninfo.rc because that is build by # config.status and thus has up-to-date version numbers. -gpg-error.h: Makefile mkheader $(parts_of_gpg_error_h) \ +gpg-error.h: Makefile mkheader$(EXEEXT_FOR_BUILD) $(parts_of_gpg_error_h) \ versioninfo.rc ../config.h $(pre_mkheader_cmds) - ./mkheader $(host_os) $(host_triplet) $(srcdir)/gpg-error.h.in \ + ./mkheader$(EXEEXT_FOR_BUILD) $(host_os) $(host_triplet) $(srcdir)/gpg-error.h.in \ ../config.h $(PACKAGE_VERSION) $(VERSION_NUMBER) >$@ gpgrt.h: gpg-error.h ----------------------------------------------------------------------- Summary of changes: src/Makefile.am | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) hooks/post-receive -- Error codes used by GnuPG et al. http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 17 11:09:11 2018 From: cvs at cvs.gnupg.org (by Maximilian Krambach) Date: Tue, 17 Jul 2018 11:09:11 +0200 Subject: [git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-75-gce0379d Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, javascript-binding has been updated via ce0379d999039131c86dc0bb83e9b8edfee1c7d4 (commit) from 5213a599fea0da64560f935dffbf6b27a39d4850 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit ce0379d999039131c86dc0bb83e9b8edfee1c7d4 Author: Maximilian Krambach Date: Tue Jul 17 11:07:49 2018 +0200 js: fix getkeys with locate option -- * src/Keyring.js: As locate will not work with the "secret" option, the first message cannot be reused, thus a new one must be created here diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index cefc812..f2a7138 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -68,8 +68,10 @@ export class GPGME_Keyring { let secondrequest; if (prepare_sync === true) { secondrequest = function() { - msg.setParameter('secret', true); - return msg.post(); + let msg2 = createMessage('keylist'); + msg2.setParameter('keys', pattern); + msg2.setParameter('secret', true); + return msg2.post(); }; } else { secondrequest = function() { ----------------------------------------------------------------------- Summary of changes: lang/js/src/Keyring.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 17 14:54:24 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Tue, 17 Jul 2018 14:54:24 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-58-g514a0d5 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via 514a0d5d0a1fba979fb2f774aa3b1d241c64cf17 (commit) via 34096e5a94a76b3f71270e4c39f7d2f333e0430b (commit) via f847b6e6d244558a1b04ae38a1b267e03a86ce3a (commit) via cf28a7508d65deaeb953074b7ddbd5b064d39177 (commit) via 3a8b92c4ee02cc08875e009527f1d8169ff65663 (commit) via 22996594617e69285ea4ddef5102fd8ecf7d017b (commit) via 6d9156a806c096e197f5efbdaefa84586db48580 (commit) from 7e76531304ec9fbd5227ed511cea0f0df68fa9e0 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 514a0d5d0a1fba979fb2f774aa3b1d241c64cf17 Author: Andre Heinecke Date: Tue Jul 17 14:53:24 2018 +0200 Fix possible invalid CloseHandle and DeleteFile * src/mail.cpp (add_attachments_o): Guard CloseHandle and DeleteFile. -- CloseHandle may only be called on valid handles. diff --git a/src/mail.cpp b/src/mail.cpp index 1843543..84776ea 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -687,8 +687,11 @@ add_attachments_o(LPDISPATCH mail, SRCNAME, __func__, dispName.c_str()); err = 1; } - CloseHandle (hFile); - if (!DeleteFileW (wchar_file)) + if (hFile && hFile != INVALID_HANDLE_VALUE) + { + CloseHandle (hFile); + } + if (wchar_file && !DeleteFileW (wchar_file)) { log_error ("%s:%s: Failed to delete tmp attachment for: %s", SRCNAME, __func__, dispName.c_str()); commit 34096e5a94a76b3f71270e4c39f7d2f333e0430b Author: Andre Heinecke Date: Tue Jul 17 14:43:12 2018 +0200 Cleanup shutdown and fix potential crashes * src/explorer-events.cpp (Close): Unregister sink with addin. * src/explorers-events.cpp (NewInstance): Register sink. * src/gpgoladdin.cpp (GpgolAddin::~GpgolAddin): Remove shutdown logic. (GpgolAddin::OnConnection): Mark shutdown state as false. (GpgolAddin::OnDisconnection): Call shutdown. (install_explorer_sinks): Register created sinks. (GpgolAddin::shutdown): New. Handle shutdown. (GpgolAddin::registerExplorerSink), (GpgolAddin::unregisterExplorerSink): Track explorer sinks. * src/gpgoladdin.h: Update accordingly. * src/mail.cpp (Mail::closeAllMails_o): Fix folder events detach and do it earlier. (Mail::installFolderEventHandler_o): Use sink instead of folder to track event handler. * src/windowmessages.cpp (add_explorer, remove_explorer): removed. (gpgol_hook): Interate over actual explorers instead of variables. * src/windowmessages.h: Update accordingly. -- This fixes Explorer events release / deletion on unload / shutdown. Previously this was only done on close, which came after GpgOL was unloaded. Maybe this resulted in a jump to an unmapped location? It also fixes that the gpgol_hook was only enabled for all explorers at start time. Maybe we will see a regression now that it works as intended on all explorers. Explorers Events and Application Events were never deleted / released because they were not detached before release. (But the release then didn't delete them). Definitely fixed is a race condition on shutdown which would be: -> Shutdown detected -> Close all mails -> The currently visible mail is closed -> Outlook loads it again because it is currently visible -> But we are in shutdown mode. Now we would start to parse while actually shutting down. This could lead to hangs / crashes. The reason for this was that we closed the mails before we detached the Application event handler and thus captured the item load again. diff --git a/src/explorer-events.cpp b/src/explorer-events.cpp index 03969b1..b9706db 100644 --- a/src/explorer-events.cpp +++ b/src/explorer-events.cpp @@ -92,7 +92,7 @@ EVENT_SINK_INVOKE(ExplorerEvents) log_oom_extra ("%s:%s: Deleting event handler: %p", SRCNAME, __func__, this); - remove_explorer (m_object); + GpgolAddin::get_instance ()->unregisterExplorerSink (this); delete this; return S_OK; } diff --git a/src/explorers-events.cpp b/src/explorers-events.cpp index d56b9a8..74dccf1 100644 --- a/src/explorers-events.cpp +++ b/src/explorers-events.cpp @@ -60,13 +60,14 @@ EVENT_SINK_INVOKE(ExplorersEvents) SRCNAME, __func__); break; } - if (!install_ExplorerEvents_sink (parms->rgvarg[0].pdispVal)) + LPDISPATCH expSink = install_ExplorerEvents_sink (parms->rgvarg[0].pdispVal); + if (!expSink) { log_error ("%s:%s: Failed to install Explorer event sink.", SRCNAME, __func__); break; - } + GpgolAddin::get_instance()->registerExplorerSink (expSink); } default: break; diff --git a/src/gpgoladdin.cpp b/src/gpgoladdin.cpp index 15fb475..7d85267 100644 --- a/src/gpgoladdin.cpp +++ b/src/gpgoladdin.cpp @@ -170,6 +170,7 @@ GpgolAddin::GpgolAddin (void) : m_lRef(0), m_applicationEventSink(nullptr), m_explorersEventSink(nullptr), m_disabled(false), + m_shutdown(false), m_hook(nullptr) { read_options (); @@ -185,15 +186,6 @@ GpgolAddin::~GpgolAddin (void) { return; } - log_debug ("%s:%s: Releasing Application Event Sink;", - SRCNAME, __func__); - gpgol_release (m_explorersEventSink); - gpgol_release (m_applicationEventSink); - - write_options (); - - UnhookWindowsHookEx (m_hook); - addin_instance = NULL; log_debug ("%s:%s: Object deleted\n", SRCNAME, __func__); @@ -316,6 +308,7 @@ GpgolAddin::OnConnection (LPDISPATCH Application, ext_ConnectMode ConnectMode, log_debug ("%s:%s: this is GpgOL %s\n", SRCNAME, __func__, PACKAGE_VERSION); + m_shutdown = false; can_unload = false; m_application = Application; m_application->AddRef(); @@ -365,18 +358,7 @@ GpgolAddin::OnDisconnection (ext_DisconnectMode RemoveMode, does not allow us any OOM calls then and only returns "Unexpected error" in that case. Weird. */ - if (Mail::closeAllMails_o ()) - { - MessageBox (NULL, - "Failed to remove plaintext from at least one message.\n\n" - "Until GpgOL is activated again it is possible that the " - "plaintext of messages decrypted in this Session is saved " - "or transfered back to your mailserver.", - _("GpgOL"), - MB_ICONINFORMATION|MB_OK); - } - - write_options(); + shutdown (); can_unload = true; return S_OK; } @@ -469,9 +451,8 @@ install_explorer_sinks (LPDISPATCH application) { log_oom_extra ("%s:%s: created sink %p for explorer %i", SRCNAME, __func__, sink, i); + GpgolAddin::get_instance ()->registerExplorerSink (sink); } - add_explorer (explorer); - gpgol_release (explorer); } /* Now install the event sink to handle new explorers */ return install_ExplorersEvents_sink (explorers); @@ -1111,3 +1092,70 @@ GpgolAddin::get_instance () } return addin_instance; } + +void +GpgolAddin::shutdown () +{ + if (m_shutdown) + { + log_debug ("%s:%s: Already shutdown", + SRCNAME, __func__); + return; + } + + /* Disabling message hook */ + UnhookWindowsHookEx (m_hook); + + log_debug ("%s:%s: Releasing Application Event Sink;", + SRCNAME, __func__); + detach_ApplicationEvents_sink (m_applicationEventSink); + gpgol_release (m_applicationEventSink); + + log_debug ("%s:%s: Releasing Explorers Event Sink;", + SRCNAME, __func__); + detach_ExplorersEvents_sink (m_explorersEventSink); + gpgol_release (m_explorersEventSink); + + log_debug ("%s:%s: Releasing Explorer Event Sinks;", + SRCNAME, __func__); + for (auto sink: m_explorerEventSinks) + { + detach_ExplorerEvents_sink (sink); + gpgol_release (sink); + } + + write_options (); + + if (Mail::closeAllMails_o ()) + { + MessageBox (NULL, + "Failed to remove plaintext from at least one message.\n\n" + "Until GpgOL is activated again it is possible that the " + "plaintext of messages decrypted in this Session is saved " + "or transfered back to your mailserver.", + _("GpgOL"), + MB_ICONINFORMATION|MB_OK); + } + m_shutdown = true; +} + +void +GpgolAddin::registerExplorerSink (LPDISPATCH sink) +{ + m_explorerEventSinks.push_back (sink); +} + +void +GpgolAddin::unregisterExplorerSink (LPDISPATCH sink) +{ + for (int i = 0; i < m_explorerEventSinks.size(); ++i) + { + if (m_explorerEventSinks[i] == sink) + { + m_explorerEventSinks.erase(m_explorerEventSinks.begin() + i); + return; + } + } + log_error ("%s:%s: Unregister %p which was not registered.", + SRCNAME, __func__, sink); +} diff --git a/src/gpgoladdin.h b/src/gpgoladdin.h index ae7ab22..05c23c0 100644 --- a/src/gpgoladdin.h +++ b/src/gpgoladdin.h @@ -26,6 +26,8 @@ #include "mymapi.h" +#include + class GpgolAddinRibbonExt; class ApplicationEventListener; @@ -203,6 +205,12 @@ public: public: static GpgolAddin * get_instance (); + + void registerExplorerSink (LPDISPATCH sink); + void unregisterExplorerSink (LPDISPATCH sink); + /* Start the shutdown. Unregisters everything and closes all + crypto mails. */ + void shutdown (); LPDISPATCH get_application () { return m_application; } private: @@ -215,7 +223,9 @@ private: LPDISPATCH m_explorersEventSink; LPDISPATCH m_ribbon_control; bool m_disabled; + bool m_shutdown; HHOOK m_hook; + std::vector m_explorerEventSinks; }; class GpgolAddinFactory: public IClassFactory diff --git a/src/mail.cpp b/src/mail.cpp index 3a25323..1843543 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -1614,6 +1614,16 @@ int Mail::closeAllMails_o () { int err = 0; + + /* Detach Folder sinks */ + for (auto fit = s_folder_events_map.begin(); fit != s_folder_events_map.end(); ++fit) + { + detach_FolderEvents_sink (fit->second); + gpgol_release (fit->second); + } + s_folder_events_map.clear(); + + std::map::iterator it; TRACEPOINT; gpgrt_lock_lock (&mail_map_lock); @@ -1645,11 +1655,6 @@ Mail::closeAllMails_o () } } } - for (auto fit = s_folder_events_map.begin(); fit != s_folder_events_map.end(); ++fit) - { - detach_FolderEvents_sink (fit->second); - } - s_folder_events_map.clear(); return err; } int @@ -3407,8 +3412,8 @@ Mail::installFolderEventHandler_o() { log_error ("%s:%s: Install folder events watcher for %s.", SRCNAME, __func__, strPath.c_str()); - install_FolderEvents_sink (folder); - s_folder_events_map.insert (std::make_pair (strPath, folder)); + const auto sink = install_FolderEvents_sink (folder); + s_folder_events_map.insert (std::make_pair (strPath, sink)); } /* Folder already registered */ diff --git a/src/windowmessages.cpp b/src/windowmessages.cpp index 0364717..76f29b8 100644 --- a/src/windowmessages.cpp +++ b/src/windowmessages.cpp @@ -313,22 +313,6 @@ do_in_ui_thread_async (gpgol_wmsg_type type, void *data, int delay) CloseHandle (CreateThread (NULL, 0, do_async, (LPVOID) ctx, 0, NULL)); } -static std::vector explorers; - -void -add_explorer (LPDISPATCH explorer) -{ - explorers.push_back (explorer); -} - -void remove_explorer (LPDISPATCH explorer) -{ - explorers.erase(std::remove(explorers.begin(), - explorers.end(), - explorer), - explorers.end()); -} - LRESULT CALLBACK gpgol_hook(int code, WPARAM wParam, LPARAM lParam) { @@ -343,12 +327,41 @@ gpgol_hook(int code, WPARAM wParam, LPARAM lParam) case WM_CLOSE: { HWND lastChild = NULL; - for (const auto explorer: explorers) + log_debug ("%s:%s: Got WM_CLOSE", + SRCNAME, __func__); + if (!GpgolAddin::get_instance() || !GpgolAddin::get_instance ()->get_application()) { + TRACEPOINT; + break; + } + LPDISPATCH explorers = get_oom_object (GpgolAddin::get_instance ()->get_application(), + "Explorers"); + + if (!explorers) + { + log_error ("%s:%s: No explorers object", + SRCNAME, __func__); + break; + } + int count = get_oom_int (explorers, "Count"); + + for (int i = 1; i <= count; i++) + { + std::string item = "Item("; + item += std::to_string (i) + ")"; + LPDISPATCH explorer = get_oom_object (explorers, item.c_str()); + + if (!explorer) + { + TRACEPOINT; + break; + } + /* Casting to LPOLEWINDOW and calling GetWindow succeeded in Outlook 2016 but always returned the number 1. So we need this hack. */ char *caption = get_oom_string (explorer, "Caption"); + gpgol_release (explorer); if (!caption) { log_debug ("%s:%s: No caption.", @@ -363,9 +376,9 @@ gpgol_hook(int code, WPARAM wParam, LPARAM lParam) if (hwnd == cwp->hwnd) { log_debug ("%s:%s: WM_CLOSE windowmessage for explorer. " - "Closing all mails.", + "Shutting down.", SRCNAME, __func__); - Mail::closeAllMails_o (); + GpgolAddin::get_instance ()->shutdown(); break; } } @@ -379,7 +392,7 @@ gpgol_hook(int code, WPARAM wParam, LPARAM lParam) { log_debug ("%s:%s: SC_CLOSE syscommand. Closing all mails.", SRCNAME, __func__); - Mail::closeAllMails_o (); + GpgolAddin::get_instance ()->shutdown(); } */ break; default: diff --git a/src/windowmessages.h b/src/windowmessages.h index 6a96a13..2d6da49 100644 --- a/src/windowmessages.h +++ b/src/windowmessages.h @@ -98,9 +98,6 @@ delayed_invalidate_ui (LPVOID); DWORD WINAPI close_mail (LPVOID); -void add_explorer (LPDISPATCH explorer); -void remove_explorer (LPDISPATCH explorer); - /* The lock to invalide the ui */ extern gpgrt_lock_t invalidate_lock; commit f847b6e6d244558a1b04ae38a1b267e03a86ce3a Author: Andre Heinecke Date: Wed Jul 11 16:48:21 2018 +0200 Tune down error to debug * src/mail.cpp (get_uid_for_sender): It's common for S/MIME to have two uids where one does not have an email. So don't error but just debug it. diff --git a/src/mail.cpp b/src/mail.cpp index fb28256..3a25323 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -1927,7 +1927,8 @@ get_uid_for_sender (const Key &k, const char *sender) { if (!uid.email() || !*(uid.email())) { - log_error ("%s:%s: skipping uid without email.", + /* This happens for S/MIME a lot */ + log_debug ("%s:%s: skipping uid without email.", SRCNAME, __func__); continue; } commit cf28a7508d65deaeb953074b7ddbd5b064d39177 Author: Andre Heinecke Date: Wed Jul 11 16:47:32 2018 +0200 Check for wchar_t conversion success for attach * src/mail.cpp (add_attachments_o): Check wchar_name. diff --git a/src/mail.cpp b/src/mail.cpp index 6c74633..fb28256 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -651,39 +651,47 @@ add_attachments_o(LPDISPATCH mail, for (auto att: attachments) { int err = 0; - if (att->get_display_name().empty()) + const auto dispName = att->get_display_name (); + if (dispName.empty()) { log_error ("%s:%s: Ignoring attachment without display name.", SRCNAME, __func__); continue; } - wchar_t* wchar_name = utf8_to_wchar (att->get_display_name().c_str()); + wchar_t* wchar_name = utf8_to_wchar (dispName.c_str()); + if (!wchar_name) + { + log_error ("%s:%s: Failed to convert '%s' to wchar.", + SRCNAME, __func__, dispName.c_str()); + continue; + } + HANDLE hFile; wchar_t* wchar_file = get_tmp_outfile (wchar_name, &hFile); if (!wchar_file) { log_error ("%s:%s: Failed to obtain a tmp filename for: %s", - SRCNAME, __func__, att->get_display_name().c_str()); + SRCNAME, __func__, dispName.c_str()); err = 1; } if (!err && copy_attachment_to_file (att, hFile)) { log_error ("%s:%s: Failed to copy attachment %s to temp file", - SRCNAME, __func__, att->get_display_name().c_str()); + SRCNAME, __func__, dispName.c_str()); err = 1; } if (!err && add_oom_attachment (mail, wchar_file, wchar_name)) { log_error ("%s:%s: Failed to add attachment: %s", - SRCNAME, __func__, att->get_display_name().c_str()); + SRCNAME, __func__, dispName.c_str()); err = 1; } CloseHandle (hFile); if (!DeleteFileW (wchar_file)) { log_error ("%s:%s: Failed to delete tmp attachment for: %s", - SRCNAME, __func__, att->get_display_name().c_str()); + SRCNAME, __func__, dispName.c_str()); err = 1; } xfree (wchar_file); commit 3a8b92c4ee02cc08875e009527f1d8169ff65663 Author: Andre Heinecke Date: Wed Jul 11 16:46:37 2018 +0200 Log sent windowmessages * src/windowmessages.cpp (do_in_ui_thread): Log message sending. diff --git a/src/windowmessages.cpp b/src/windowmessages.cpp index c371886..0364717 100644 --- a/src/windowmessages.cpp +++ b/src/windowmessages.cpp @@ -275,6 +275,10 @@ do_in_ui_thread (gpgol_wmsg_type type, void *data) wm_ctx_t ctx = {NULL, UNKNOWN, 0, 0}; ctx.wmsg_type = type; ctx.data = data; + + log_debug ("%s:%s: Sending message of type %i", + SRCNAME, __func__, type); + if (send_msg_to_ui_thread (&ctx)) { return -1; commit 22996594617e69285ea4ddef5102fd8ecf7d017b Author: Andre Heinecke Date: Wed Jul 11 16:46:14 2018 +0200 Minor improvement to debug output -- diff --git a/src/common.cpp b/src/common.cpp index feb68ff..b118dff 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -425,7 +425,7 @@ get_tmp_outfile (wchar_t *name, HANDLE *outHandle) FILE_ATTRIBUTE_TEMPORARY, NULL)) == INVALID_HANDLE_VALUE) { - log_debug_w32 (-1, "%s:%s: Failed to open candidate %S.", + log_debug_w32 (-1, "%s:%s: Failed to open candidate '%S'", SRCNAME, __func__, outName); wchar_t fnameBuf[MAX_PATH + 1]; wchar_t origName[MAX_PATH + 1]; commit 6d9156a806c096e197f5efbdaefa84586db48580 Author: Andre Heinecke Date: Wed Jul 11 16:45:22 2018 +0200 Check if someone tries to set null as att name * src/attachment.cpp (Attachment::set_display_name): Check for NULL. -- Should not happen but better save then sorry diff --git a/src/attachment.cpp b/src/attachment.cpp index 783272c..68f8025 100644 --- a/src/attachment.cpp +++ b/src/attachment.cpp @@ -43,6 +43,12 @@ Attachment::get_display_name() const void Attachment::set_display_name(const char *name) { + if (!name) + { + log_error ("%s:%s: Display name set to null.", + SRCNAME, __func__); + return; + } m_utf8DisplayName = std::string(name); } ----------------------------------------------------------------------- Summary of changes: src/attachment.cpp | 6 ++++ src/common.cpp | 2 +- src/explorer-events.cpp | 2 +- src/explorers-events.cpp | 5 +-- src/gpgoladdin.cpp | 94 ++++++++++++++++++++++++++++++++++++------------ src/gpgoladdin.h | 10 ++++++ src/mail.cpp | 49 ++++++++++++++++--------- src/windowmessages.cpp | 57 ++++++++++++++++++----------- src/windowmessages.h | 3 -- 9 files changed, 162 insertions(+), 66 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 17 15:05:55 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Tue, 17 Jul 2018 15:05:55 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-59-gd719c98 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via d719c98902827d07af7619c9d19b4f2752bd0862 (commit) from 514a0d5d0a1fba979fb2f774aa3b1d241c64cf17 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit d719c98902827d07af7619c9d19b4f2752bd0862 Author: Andre Heinecke Date: Tue Jul 17 15:04:19 2018 +0200 Load gpgconf in a background thread * src/cpphelp.cpp (is_de_vs): Set checked earlier for better reentrancy. * src/gpgoladdin.cpp (OnStartupComplete): init_gpgme_config. -- GpgME++ already handles caching for us. All we have to do is trigger loading early and in a non-blocking manner. diff --git a/src/cpphelp.cpp b/src/cpphelp.cpp index c09b16d..20e4794 100644 --- a/src/cpphelp.cpp +++ b/src/cpphelp.cpp @@ -112,6 +112,7 @@ in_de_vs_mode() { return vs_mode; } + checked = true; GpgME::Error err; const auto components = GpgME::Configuration::Component::load (err); log_debug ("%s:%s: Checking for de-vs mode.", @@ -120,7 +121,6 @@ in_de_vs_mode() { log_error ("%s:%s: Failed to get gpgconf components: %s", SRCNAME, __func__, err.asString ()); - checked = true; vs_mode = false; return vs_mode; } @@ -136,17 +136,14 @@ in_de_vs_mode() { log_debug ("%s:%s: Detected de-vs mode", SRCNAME, __func__); - checked = true; vs_mode = true; return vs_mode; } } - checked = true; vs_mode = false; return vs_mode; } } - checked = true; vs_mode = false; return false; } diff --git a/src/gpgoladdin.cpp b/src/gpgoladdin.cpp index 7d85267..220602b 100644 --- a/src/gpgoladdin.cpp +++ b/src/gpgoladdin.cpp @@ -46,6 +46,7 @@ #include "windowmessages.h" #include "mail.h" #include "addin-options.h" +#include "cpphelp.h" #include #include @@ -458,6 +459,18 @@ install_explorer_sinks (LPDISPATCH application) return install_ExplorersEvents_sink (explorers); } +static DWORD WINAPI +init_gpgme_config (LPVOID) +{ + /* This is a check we need to do anyway. GpgME++ caches + the configuration once it is accessed for the first time + so this call also initializes GpgME++ */ + bool de_vs_mode = in_de_vs_mode (); + log_debug ("%s:%s: init_gpgme_config de_vs_mode %i", + SRCNAME, __func__, de_vs_mode); + return 0; +} + STDMETHODIMP GpgolAddin::OnStartupComplete (SAFEARRAY** custom) { @@ -495,6 +508,9 @@ GpgolAddin::OnStartupComplete (SAFEARRAY** custom) m_applicationEventSink = install_ApplicationEvents_sink (m_application); m_explorersEventSink = install_explorer_sinks (m_application); check_html_preferred (); + + CloseHandle (CreateThread (NULL, 0, init_gpgme_config, nullptr, 0, + NULL)); return S_OK; } ----------------------------------------------------------------------- Summary of changes: src/cpphelp.cpp | 5 +---- src/gpgoladdin.cpp | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 17 16:57:25 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Tue, 17 Jul 2018 16:57:25 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-61-g1e699af Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via 1e699afd9531c6d0e4d7bde3efcdf5a323fc02a7 (commit) via 1ff79faa4adb181a266531ee39166d8a4af459c1 (commit) from d719c98902827d07af7619c9d19b4f2752bd0862 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 1e699afd9531c6d0e4d7bde3efcdf5a323fc02a7 Author: Andre Heinecke Date: Tue Jul 17 16:54:43 2018 +0200 Rewrite get_tmp_outfile to fix a crash * src/common.cpp (get_tmp_outfile): Rewrite using c++. (getTmpPathUtf8, CreateFileUtf8): New helpers. -- This fixes a crash because somehow snwprintf didn't always work as I expeted it to. In that case it would only concatenate the first chars of the attachment filenames this caused the wcsrchr of the backslash to return NULL and the following wcschr to find the extension to crash. This happend on a name conflict in the tmp folder. E.g. if two mails were open with the same attachment filenames. diff --git a/src/common.cpp b/src/common.cpp index b118dff..689a0b9 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -386,75 +386,127 @@ get_pretty_attachment_name (wchar_t *path, protocol_t protocol, return pretty; } -/* Open a file in a temporary directory, take name as a - suggestion and put the open Handle in outHandle. - Returns the actually used file name in case there - were other files with that name. */ -wchar_t* -get_tmp_outfile (wchar_t *name, HANDLE *outHandle) +static HANDLE +CreateFileUtf8 (const char *utf8Name) { - wchar_t tmpPath[MAX_PATH]; - wchar_t *outName; - wchar_t *fileExt = NULL; - int tries = 1; + if (!utf8Name) + { + return INVALID_HANDLE_VALUE; + } - if (!name || !wcslen(name)) + wchar_t *wname = utf8_to_wchar (utf8Name); + if (!wname) { - log_error ("%s:%s: Needs a name.", - SRCNAME, __func__); - return NULL; + TRACEPOINT; + return INVALID_HANDLE_VALUE; } + auto ret = CreateFileW (wname, + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_DELETE, + NULL, + CREATE_NEW, + FILE_ATTRIBUTE_TEMPORARY, + NULL); + xfree (wname); + return ret; +} + +static std::string +getTmpPathUtf8 () +{ + static std::string ret; + if (!ret.empty()) + { + return ret; + } + wchar_t tmpPath[MAX_PATH + 2]; + if (!GetTempPathW (MAX_PATH, tmpPath)) { log_error ("%s:%s: Could not get tmp path.", SRCNAME, __func__); - return NULL; + return ret; } - outName = (wchar_t*) xmalloc ((MAX_PATH + 1) * sizeof(wchar_t)); - memset (outName, 0, (MAX_PATH + 1) * sizeof (wchar_t)); + char *utf8Name = wchar_to_utf8 (tmpPath); - snwprintf (outName, MAX_PATH, L"%s%s", tmpPath, name); + if (!utf8Name) + { + TRACEPOINT; + return ret; + } + ret = utf8Name; + xfree (utf8Name); + return ret; +} - while ((*outHandle = CreateFileW (outName, - GENERIC_WRITE | GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_DELETE, - NULL, - CREATE_NEW, - FILE_ATTRIBUTE_TEMPORARY, - NULL)) == INVALID_HANDLE_VALUE) +/* Open a file in a temporary directory, take name as a + suggestion and put the open Handle in outHandle. + Returns the actually used file name in case there + were other files with that name. */ +wchar_t* +get_tmp_outfile (wchar_t *name, HANDLE *outHandle) +{ + const auto utf8Name = wchar_to_utf8_string (name); + const auto tmpPath = getTmpPathUtf8 (); + + if (utf8Name.empty() || tmpPath.empty()) + { + TRACEPOINT; + return nullptr; + } + + auto outName = tmpPath + utf8Name; + + log_mime_parser("%s:%s: Attachment candidate is %s", + SRCNAME, __func__, outName.c_str ()); + + int tries = 1; + while ((*outHandle = CreateFileUtf8 (outName.c_str ())) == INVALID_HANDLE_VALUE) { - log_debug_w32 (-1, "%s:%s: Failed to open candidate '%S'", - SRCNAME, __func__, outName); - wchar_t fnameBuf[MAX_PATH + 1]; - wchar_t origName[MAX_PATH + 1]; - memset (fnameBuf, 0, MAX_PATH + 1); - memset (origName, 0, MAX_PATH + 1); + log_debug_w32 (-1, "%s:%s: Failed to open candidate '%s'", + SRCNAME, __func__, outName.c_str()); + + char *outNameC = strdup (outName.c_str()); + + const auto lastBackslash = strrchr (outNameC, '\\'); + if (!lastBackslash) + { + /* This is an error because tmp name by definition contains one */ + log_error ("%s:%s: No backslash in origname '%s'", + SRCNAME, __func__, outNameC); + xfree (outNameC); + return NULL; + } - snwprintf (origName, MAX_PATH, L"%s%s", tmpPath, name); - fileExt = wcschr (wcsrchr(origName, '\\'), '.'); + auto fileExt = strchr (lastBackslash, '.'); if (fileExt) { - wcsncpy (fnameBuf, origName, fileExt - origName); + *fileExt = '\0'; + ++fileExt; } - else + // OutNameC is now without an extension and if + // there is a file ext it now points to the extension. + + outName = tmpPath + outNameC + std::to_string(tries++); + + if (fileExt) { - wcsncpy (fnameBuf, origName, wcslen (origName)); + outName += fileExt; } - snwprintf (outName, MAX_PATH, L"%s%i%s", fnameBuf, tries++, - fileExt ? fileExt : L""); + xfree (outNameC); + if (tries > 100) { /* You have to know when to give up,.. */ log_error ("%s:%s: Could not get a name out of 100 tries", SRCNAME, __func__); - xfree (outName); return NULL; } } - return outName; + return utf8_to_wchar (outName.c_str ()); } /** Get the Gpg4win Install directory. commit 1ff79faa4adb181a266531ee39166d8a4af459c1 Author: Andre Heinecke Date: Tue Jul 17 16:53:43 2018 +0200 Add wchar_to_utf8_string function * src/w32-gettext.cpp, src/w32-gettext.h (wchar_to_utf8_string): Wrap the c to c++ conversion in a function. diff --git a/src/w32-gettext.cpp b/src/w32-gettext.cpp index 0f67673..b89bc79 100644 --- a/src/w32-gettext.cpp +++ b/src/w32-gettext.cpp @@ -1515,6 +1515,26 @@ wchar_to_utf8 (const wchar_t *string) return result; } +std::string +wchar_to_utf8_string (const wchar_t *string) +{ + std::string ret; + if (!string) + { + return ret; + } + + const auto utf8 = wchar_to_utf8 (string); + if (!utf8) + { + return ret; + } + ret = utf8; + + xfree (utf8); + return ret; +} + /* Convert UTF8 to the native codepage. This function is guaranteed to never return NULL. Caller must xfree the return value. */ diff --git a/src/w32-gettext.h b/src/w32-gettext.h index cf72888..7010586 100644 --- a/src/w32-gettext.h +++ b/src/w32-gettext.h @@ -73,4 +73,6 @@ char *native_to_utf8 (const char *string); #ifdef __cplusplus } +#include +std::string wchar_to_utf8_string (const wchar_t *string); #endif ----------------------------------------------------------------------- Summary of changes: src/common.cpp | 132 ++++++++++++++++++++++++++++++++++++---------------- src/w32-gettext.cpp | 20 ++++++++ src/w32-gettext.h | 2 + 3 files changed, 114 insertions(+), 40 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 18 11:30:32 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Wed, 18 Jul 2018 11:30:32 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-95-g16462c5 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 16462c54b3503e77bc48c2486234531d7bc31b6d (commit) from 1686e07e77a1eee3b2708d0231a5a549956021f7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 16462c54b3503e77bc48c2486234531d7bc31b6d Author: Andre Heinecke Date: Wed Jul 18 11:27:46 2018 +0200 qt: Handle encoding for diagnostics * lang/qt/src/threadedjobmixin.cpp (fromEncoding) (stringFromGpgOutput): New helpers. (markupDiagnostics): Use it. -- The Problem is that on my western windows system GnuPG gets CP 437 as GetConsoleOutputCP and prints in that codepage. In a W32 GUI Application we get 0 as GetConsoleOutputCP and 1252 with GetACP. The only thing that seemed to somehow match was GetOEMCP but that might just be luck and it might still be broken in other windows languages. This code is also used in Kleopatra so it might make sense to make it public once it is demonstrated that it works on most systems. diff --git a/lang/qt/src/threadedjobmixin.cpp b/lang/qt/src/threadedjobmixin.cpp index 8fed77c..cd7c494 100644 --- a/lang/qt/src/threadedjobmixin.cpp +++ b/lang/qt/src/threadedjobmixin.cpp @@ -53,6 +53,58 @@ using namespace QGpgME; using namespace GpgME; +#ifdef Q_OS_WIN +#include + +static QString fromEncoding (unsigned int src_encoding, const char *data) +{ + int n = MultiByteToWideChar(src_encoding, 0, data, -1, NULL, 0); + if (n < 0) { + return QString(); + } + + wchar_t *result = (wchar_t *) malloc ((n+1) * sizeof *result); + + n = MultiByteToWideChar(src_encoding, 0, data, -1, result, n); + if (n < 0) { + free(result); + return QString(); + } + const auto ret = QString::fromWCharArray(result, n); + free(result); + return ret; +} +#endif + +static QString stringFromGpgOutput(const QByteArray &ba) +{ +#ifdef Q_OS_WIN + /* Qt on Windows uses GetACP while GnuPG prefers + * GetConsoleOutputCP. + * + * As we are not a console application GetConsoleOutputCP + * usually returns 0. + * From experience the closest thing that let's us guess + * what GetConsoleOutputCP returns for a console application + * it appears to be the OEMCP. + */ + unsigned int cpno = GetConsoleOutputCP (); + if (!cpno) { + cpno = GetOEMCP(); + } + if (!cpno) { + cpno = GetACP(); + } + if (!cpno) { + return QString(); + } + + return fromEncoding(cpno, ba.constData()); +#else + return QString::fromLocal8Bit(ba); +#endif +} + static QString markupDiagnostics(const QString &data) { // First ensure that we don't have html in the diag. @@ -76,7 +128,7 @@ QString _detail::audit_log_as_html(Context *ctx, GpgME::Error &err) return QString::fromLocal8Bit(err.asString()); } const QByteArray ba = dp.data(); - return markupDiagnostics(QString::fromUtf8(ba.data(), ba.size())); + return markupDiagnostics(stringFromGpgOutput(ba)); } if (ctx->protocol() == CMS) { ----------------------------------------------------------------------- Summary of changes: lang/qt/src/threadedjobmixin.cpp | 54 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 18 13:08:33 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Wed, 18 Jul 2018 13:08:33 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-98-g6d7b438 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 6d7b4382c3e12ba1dbbd0762dfa850c76750d838 (commit) via 82e4b900a96c837392259469a9a5821a95e7a707 (commit) via b78140daf7720132711314a4e5ed878b49da99f4 (commit) from 16462c54b3503e77bc48c2486234531d7bc31b6d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 6d7b4382c3e12ba1dbbd0762dfa850c76750d838 Author: Andre Heinecke Date: Wed Jul 18 13:06:08 2018 +0200 json: Ensure that native msging request is string * src/gpgme-json.c (native_messaging_repl): Ensure that the request is NULL terminated. -- This avoids potential memory leaks and access to unmapped memory in case the request was not terminated. Other request functions use es_read_line which gurantees NULL termination. diff --git a/src/gpgme-json.c b/src/gpgme-json.c index edd3d32..74ca2b6 100644 --- a/src/gpgme-json.c +++ b/src/gpgme-json.c @@ -3601,7 +3601,7 @@ native_messaging_repl (void) } /* Read request. */ - request = xtrymalloc (nrequest); + request = xtrymalloc (nrequest + 1); if (!request) { err = gpg_error_from_syserror (); @@ -3626,6 +3626,7 @@ native_messaging_repl (void) } else /* Process request */ { + request[n] = '\0'; /* Esnure that request has an end */ if (opt_debug) log_debug ("request='%s'\n", request); xfree (response); commit 82e4b900a96c837392259469a9a5821a95e7a707 Author: Andre Heinecke Date: Wed Jul 18 13:02:32 2018 +0200 json: Fix crash by ensuring response is never NULL * src/gpgme-json.c (encode_and_chunk): Try to always return at least an error. (process_request): Double check that it does not return NULL. -- If process_request returns NULL the following strlen on it would crash. diff --git a/src/gpgme-json.c b/src/gpgme-json.c index 87b40a2..edd3d32 100644 --- a/src/gpgme-json.c +++ b/src/gpgme-json.c @@ -1473,13 +1473,28 @@ encode_and_chunk (cjson_t request, cjson_t response) data = cJSON_PrintUnformatted (response); if (!data) - goto leave; + { + err = GPG_ERR_NO_DATA; + goto leave; + } + + if (!request) + { + err = GPG_ERR_INV_VALUE; + goto leave; + } if ((err = get_chunksize (request, &chunksize))) - goto leave; + { + err = GPG_ERR_INV_VALUE; + goto leave; + } if (!chunksize) - goto leave; + { + err = GPG_ERR_INV_VALUE; + goto leave; + } pending_data.buffer = data; /* Data should already be encoded so that it does not @@ -1500,14 +1515,22 @@ encode_and_chunk (cjson_t request, cjson_t response) leave: xfree (getmore_request); + if (!err && !data) + { + err = GPG_ERR_GENERAL; + } + if (err) { cjson_t err_obj = gpg_error_object (NULL, err, "Encode and chunk failed: %s", gpgme_strerror (err)); + xfree (data); if (opt_interactive) - return cJSON_Print (err_obj); - return cJSON_PrintUnformatted (err_obj); + data = cJSON_Print (err_obj); + data = cJSON_PrintUnformatted (err_obj); + + cJSON_Delete (err_obj); } return data; @@ -3187,13 +3210,26 @@ process_request (const char *request) else res = cJSON_PrintUnformatted (response); } - else if (json) + else res = encode_and_chunk (json, response); if (!res) - log_error ("Printing JSON data failed\n"); + { + log_error ("Printing JSON data failed\n"); + cjson_t err_obj = error_object (NULL, "Printing JSON data failed"); + if (opt_interactive) + res = cJSON_Print (err_obj); + res = cJSON_PrintUnformatted (err_obj); + cJSON_Delete (err_obj); + } cJSON_Delete (json); cJSON_Delete (response); + + if (!res) + { + /* Can't happen unless we created a broken error_object above */ + return strdup ("Bug: Fatal error in process request\n"); + } return res; } commit b78140daf7720132711314a4e5ed878b49da99f4 Author: Andre Heinecke Date: Wed Jul 18 12:57:51 2018 +0200 json: Fix memory errors in create_keylist_patterns * src/gpgme-json.c (create_keylist_patterns): Reserve two pointers more then linefeeds. (create_keylist_patterns): Fix loop to count linebreaks. (create_keylist_patterns): Use calloc for good measure. -- This fixes crashes and memory corruption as cnt did not match i. diff --git a/src/gpgme-json.c b/src/gpgme-json.c index 06f09ef..87b40a2 100644 --- a/src/gpgme-json.c +++ b/src/gpgme-json.c @@ -691,17 +691,17 @@ create_keylist_patterns (cjson_t request, const char *name) char *p; char *tmp; char **ret; - int cnt = 1; + int cnt = 2; /* Last NULL and one is not newline delimited */ int i = 0; if (get_keys (request, name, &keystring)) return NULL; - for (p = keystring; p; p++) + for (p = keystring; *p; p++) if (*p == '\n') cnt++; - ret = xmalloc (cnt * sizeof *ret); + ret = xcalloc (1, cnt * sizeof *ret); for (p = keystring, tmp = keystring; *p; p++) { @@ -712,8 +712,7 @@ create_keylist_patterns (cjson_t request, const char *name) tmp = p + 1; } /* The last key is not newline delimted. */ - ret[i++] = *tmp ? xstrdup (tmp) : NULL; - ret[i] = NULL; + ret[i] = *tmp ? xstrdup (tmp) : NULL; xfree (keystring); return ret; ----------------------------------------------------------------------- Summary of changes: src/gpgme-json.c | 62 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 13 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 18 13:15:57 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Wed, 18 Jul 2018 13:15:57 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-99-g98a75a1 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 98a75a16ccdfe51799a27894d2eb26dba04b34f2 (commit) from 6d7b4382c3e12ba1dbbd0762dfa850c76750d838 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 98a75a16ccdfe51799a27894d2eb26dba04b34f2 Author: Andre Heinecke Date: Wed Jul 18 13:15:02 2018 +0200 json: Fix memleak in native msging repl * src/gpgme-json.c (native_messaging_repl): Free request and response after each loop. -- If we only accept once request we should not loop. If we loop we should do it properly. diff --git a/src/gpgme-json.c b/src/gpgme-json.c index 74ca2b6..cc3abfe 100644 --- a/src/gpgme-json.c +++ b/src/gpgme-json.c @@ -3665,6 +3665,10 @@ native_messaging_repl (void) log_error ("error writing request: %s\n", gpg_strerror (err)); break; } + xfree (response); + response = NULL; + xfree (request); + request = NULL; } xfree (response); ----------------------------------------------------------------------- Summary of changes: src/gpgme-json.c | 4 ++++ 1 file changed, 4 insertions(+) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 18 13:43:09 2018 From: cvs at cvs.gnupg.org (by Maximilian Krambach) Date: Wed, 18 Jul 2018 13:43:09 +0200 Subject: [git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-76-g50da3ff Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, javascript-binding has been updated via 50da3ff2fddf0d35541f798313e881fef3cff869 (commit) from ce0379d999039131c86dc0bb83e9b8edfee1c7d4 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 50da3ff2fddf0d35541f798313e881fef3cff869 Author: Maximilian Krambach Date: Wed Jul 18 13:43:47 2018 +0200 js: typo in comment -- * Documentation typo that caused jsdoc to exit with an error diff --git a/lang/js/src/permittedOperations.js b/lang/js/src/permittedOperations.js index b5e9157..1c28ab8 100644 --- a/lang/js/src/permittedOperations.js +++ b/lang/js/src/permittedOperations.js @@ -28,7 +28,7 @@ * Currently accepted values are 'number', 'string', 'boolean'. * @property {Boolean} array_allowed If the value can be an array of types * defined in allowed - * @property {} allowed_data (optional) restricts to the given values + * @property {Array<*>} allowed_data (optional) restricts to the given values */ /** ----------------------------------------------------------------------- Summary of changes: lang/js/src/permittedOperations.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 18 14:21:05 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Wed, 18 Jul 2018 14:21:05 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-66-g7f050d6 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via 7f050d64eabf781a737b1890c839d64a51c6bef6 (commit) via 9c9edde2fbae79a41f9b13b79345692795a2c036 (commit) via 128a1570c1b2af58733081aca237247d92129600 (commit) via 9c0216de9a552a2ec5060fe426bdef51803aad02 (commit) via aee94ccce1f3df1ef769197b1b2f7f693eac56ee (commit) from 1e699afd9531c6d0e4d7bde3efcdf5a323fc02a7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 7f050d64eabf781a737b1890c839d64a51c6bef6 Author: Andre Heinecke Date: Wed Jul 18 14:04:03 2018 +0200 Minor performance improvement * src/parsecontroller.cpp (ParseController::parse): Check that get_ultimate_keys is only called once even for multisigs. diff --git a/src/parsecontroller.cpp b/src/parsecontroller.cpp index 29e5b30..323b1d3 100644 --- a/src/parsecontroller.cpp +++ b/src/parsecontroller.cpp @@ -448,22 +448,25 @@ ParseController::parse() SRCNAME, __func__, this, m_decrypt_result.error().code(), m_verify_result.error().code()); - TRACEPOINT; - bool has_valid_encrypted_checksum = false; /* Ensure that the Keys for the signatures are available and if it has a valid encrypted checksum. */ + bool ultimate_keys_queried = false; for (const auto sig: m_verify_result.signatures()) { has_valid_encrypted_checksum = is_valid_chksum (sig); + /* FIXME: This is very expensive. We need some caching here + or reduce the information */ sig.key(true, true); - if (sig.validity() == Signature::Validity::Full || - sig.validity() == Signature::Validity::Ultimate) + if (!ultimate_keys_queried && + (sig.validity() == Signature::Validity::Full || + sig.validity() == Signature::Validity::Ultimate)) { /* Ensure that we have the keys with ultimate trust cached for the ui. */ get_ultimate_keys (); + ultimate_keys_queried = true; } } commit 9c9edde2fbae79a41f9b13b79345692795a2c036 Author: Andre Heinecke Date: Wed Jul 18 14:03:23 2018 +0200 Print binary mime data as hex * src/mimedataprovider.cpp (MimeDataProvider::read): Dump binary as hex. diff --git a/src/mimedataprovider.cpp b/src/mimedataprovider.cpp index 2b48382..92be963 100644 --- a/src/mimedataprovider.cpp +++ b/src/mimedataprovider.cpp @@ -558,11 +558,21 @@ MimeDataProvider::read(void *buffer, size_t size) log_mime_parser ("%s:%s: Reading: " SIZE_T_FORMAT "Bytes", SRCNAME, __func__, size); ssize_t bRead = m_crypto_data.read (buffer, size); - if (opt.enable_debug & DBG_MIME_PARSER) + if (opt.enable_debug & DBG_MIME_PARSER && bRead) { std::string buf ((char *)buffer, bRead); - log_mime_parser ("%s:%s: Data: \"%s\"", - SRCNAME, __func__, buf.c_str()); + + if (!is_binary (buf)) + { + log_mime_parser ("%s:%s: Data: \n------\n%s\n------", + SRCNAME, __func__, buf.c_str()); + } + else + { + log_mime_parser ("%s:%s: Hex Data: \n------\n%s\n------", + SRCNAME, __func__, + string_to_hex (buf).c_str ()); + } } return bRead; } commit 128a1570c1b2af58733081aca237247d92129600 Author: Andre Heinecke Date: Wed Jul 18 14:02:26 2018 +0200 Minor perfomance improvement * src/mail.cpp (level_4_check): Reduce copies of get_ultimate_keys vector. diff --git a/src/mail.cpp b/src/mail.cpp index 1ea2a15..f2f99f4 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -2236,6 +2236,7 @@ level_4_check (const UserID &uid) } if (uid.validity () == UserID::Validity::Full) { + const auto ultimate_keys = ParseController::get_ultimate_keys (); for (const auto sig: uid.signatures ()) { const char *sigID = sig.signerKeyID (); @@ -2249,7 +2250,7 @@ level_4_check (const UserID &uid) through gnupg so we cached the keys with ultimate trust during parsing and now see if we find a direct trust path.*/ - for (const auto secKey: ParseController::get_ultimate_keys ()) + for (const auto secKey: ultimate_keys) { /* Check that the Key id of the key matches */ const char *secKeyID = secKey.keyID (); commit 9c0216de9a552a2ec5060fe426bdef51803aad02 Author: Andre Heinecke Date: Wed Jul 18 14:00:53 2018 +0200 Only treat unknown sigs as lvl2 if they are valid * src/mail.cpp (Mail::updateSigstate): Check for sigsum valid before using WKD as shortcut to lvl 2. -- Using GPGME's sigstate is clunky. diff --git a/src/mail.cpp b/src/mail.cpp index 84776ea..1ea2a15 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -1987,7 +1987,8 @@ Mail::updateSigstate () m_is_signed = true; m_uid = get_uid_for_sender (sig.key(), sender.c_str()); - if (m_uid.origin() == GpgME::Key::OriginWKD && + if ((sig.summary() & Signature::Summary::Valid) && + m_uid.origin() == GpgME::Key::OriginWKD && (sig.validity() == Signature::Validity::Unknown || sig.validity() == Signature::Validity::Marginal)) { commit aee94ccce1f3df1ef769197b1b2f7f693eac56ee Author: Andre Heinecke Date: Wed Jul 18 13:59:45 2018 +0200 Add helper functions for hexdump * src/cpphelp.cpp, src/cpphelp.h (is_binary, string_to_hex): New. diff --git a/src/cpphelp.cpp b/src/cpphelp.cpp index 20e4794..2dc25a4 100644 --- a/src/cpphelp.cpp +++ b/src/cpphelp.cpp @@ -254,3 +254,39 @@ gpgol_split (const std::string &s, char delim) internal_split (s, delim, std::back_inserter (elems)); return elems; } + +std::string +string_to_hex(const std::string& input) +{ + static const char* const lut = "0123456789ABCDEF"; + size_t len = input.length(); + + std::string output; + output.reserve (3 * len + (len * 3 / 26)); + for (size_t i = 0; i < len; ++i) + { + const unsigned char c = input[i]; + output.push_back (lut[c >> 4]); + output.push_back (lut[c & 15]); + output.push_back (' '); + if (i % 26 == 0) + { + output.push_back ('\n'); + } + } + return output; +} + +bool +is_binary (const std::string &input) +{ + for (int i = 0; i < input.size() - 1; ++i) + { + const unsigned char c = input[i]; + if (c < 32 && c != 0x0d && c != 0x0a) + { + return true; + } + } + return false; +} diff --git a/src/cpphelp.h b/src/cpphelp.h index 953f861..654ab19 100644 --- a/src/cpphelp.h +++ b/src/cpphelp.h @@ -46,5 +46,11 @@ bool in_de_vs_mode (); /* Get a map of all subkey value pairs in a registry key */ std::map get_registry_subkeys (const char *path); -std::vector gpgol_split(const std::string &s, char delim); +std::vector gpgol_split (const std::string &s, char delim); + +/* Convert a string to a hex representation */ +std::string string_to_hex (const std::string& input); + +/* Check if a string contains a char < 32 */ +bool is_binary (const std::string &input); #endif // CPPHELP_H ----------------------------------------------------------------------- Summary of changes: src/cpphelp.cpp | 36 ++++++++++++++++++++++++++++++++++++ src/cpphelp.h | 8 +++++++- src/mail.cpp | 6 ++++-- src/mimedataprovider.cpp | 16 +++++++++++++--- src/parsecontroller.cpp | 11 +++++++---- 5 files changed, 67 insertions(+), 10 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 18 14:34:39 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Wed, 18 Jul 2018 14:34:39 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-67-g5e2078d Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via 5e2078d4f6686823d9a6c7a69490ccf02144ce4c (commit) from 7f050d64eabf781a737b1890c839d64a51c6bef6 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 5e2078d4f6686823d9a6c7a69490ccf02144ce4c Author: Andre Heinecke Date: Wed Jul 18 14:32:40 2018 +0200 Only shutdown for the last explorer close * src/windowmessages.cpp (gpgol_hook): Only shutdown if the last explorer is closed. -- This acidentally mostly worked before as we only registered the first explorer for this function in the past. Also added a comment remembering what this function actually intends and why it is needed. diff --git a/src/windowmessages.cpp b/src/windowmessages.cpp index 76f29b8..3861127 100644 --- a/src/windowmessages.cpp +++ b/src/windowmessages.cpp @@ -322,6 +322,10 @@ gpgol_hook(int code, WPARAM wParam, LPARAM lParam) before it reaches outlook. */ LPCWPSTRUCT cwp = (LPCWPSTRUCT) lParam; + /* What we do here is that we catch all WM_CLOSE messages that + get to Outlook. Then we check if the last open Explorer + is the target of the close. In set case we start our shutdown + routine before we pass the WM_CLOSE to outlook */ switch (cwp->message) { case WM_CLOSE: @@ -345,42 +349,46 @@ gpgol_hook(int code, WPARAM wParam, LPARAM lParam) } int count = get_oom_int (explorers, "Count"); - for (int i = 1; i <= count; i++) + if (count != 1) { - std::string item = "Item("; - item += std::to_string (i) + ")"; - LPDISPATCH explorer = get_oom_object (explorers, item.c_str()); + log_debug ("%s:%s: More then one explorer. Not shutting down.", + SRCNAME, __func__); + gpgol_release (explorers); + break; + } + + LPDISPATCH explorer = get_oom_object (explorers, "Item(1)"); + gpgol_release (explorers); - if (!explorer) - { - TRACEPOINT; - break; - } + if (!explorer) + { + TRACEPOINT; + break; + } - /* Casting to LPOLEWINDOW and calling GetWindow - succeeded in Outlook 2016 but always returned - the number 1. So we need this hack. */ - char *caption = get_oom_string (explorer, "Caption"); - gpgol_release (explorer); - if (!caption) - { - log_debug ("%s:%s: No caption.", - SRCNAME, __func__); - continue; - } - /* rctrl_renwnd32 is the window class of outlook. */ - HWND hwnd = FindWindowExA(NULL, lastChild, "rctrl_renwnd32", - caption); - xfree (caption); - lastChild = hwnd; - if (hwnd == cwp->hwnd) - { - log_debug ("%s:%s: WM_CLOSE windowmessage for explorer. " - "Shutting down.", - SRCNAME, __func__); - GpgolAddin::get_instance ()->shutdown(); - break; - } + /* Casting to LPOLEWINDOW and calling GetWindow + succeeded in Outlook 2016 but always returned + the number 1. So we need this hack. */ + char *caption = get_oom_string (explorer, "Caption"); + gpgol_release (explorer); + if (!caption) + { + log_debug ("%s:%s: No caption.", + SRCNAME, __func__); + break; + } + /* rctrl_renwnd32 is the window class of outlook. */ + HWND hwnd = FindWindowExA(NULL, lastChild, "rctrl_renwnd32", + caption); + xfree (caption); + lastChild = hwnd; + if (hwnd == cwp->hwnd) + { + log_debug ("%s:%s: WM_CLOSE windowmessage for explorer. " + "Shutting down.", + SRCNAME, __func__); + GpgolAddin::get_instance ()->shutdown(); + break; } break; } ----------------------------------------------------------------------- Summary of changes: src/windowmessages.cpp | 74 ++++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 33 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 19 10:02:28 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 19 Jul 2018 10:02:28 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-101-gaf2c74d Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via af2c74d6c06a9fb08f7de15d41162d09f871a62e (commit) via f42cd70f18d53df47cc2d027bade736377d39b71 (commit) from 98a75a16ccdfe51799a27894d2eb26dba04b34f2 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit af2c74d6c06a9fb08f7de15d41162d09f871a62e Author: Werner Koch Date: Thu Jul 19 09:46:57 2018 +0200 json: Don't use strdup but the xtrystrdup wrapper. * src/gpgme-json.c (create_keylist_patterns): Use CNT as first arg for xcalloc. (process_request): s/strdup/xtrystrdup/. -- calloc takes two arguments so to be able to detect integer overflow. Thus if we switch from malloc to calloc we should utilize that. Signed-off-by: Werner Koch diff --git a/src/gpgme-json.c b/src/gpgme-json.c index cc3abfe..81b70aa 100644 --- a/src/gpgme-json.c +++ b/src/gpgme-json.c @@ -701,7 +701,7 @@ create_keylist_patterns (cjson_t request, const char *name) if (*p == '\n') cnt++; - ret = xcalloc (1, cnt * sizeof *ret); + ret = xcalloc (cnt, sizeof *ret); for (p = keystring, tmp = keystring; *p; p++) { @@ -3214,8 +3214,11 @@ process_request (const char *request) res = encode_and_chunk (json, response); if (!res) { - log_error ("Printing JSON data failed\n"); - cjson_t err_obj = error_object (NULL, "Printing JSON data failed"); + cjson_t err_obj; + + log_error ("printing JSON data failed\n"); + + err_obj = error_object (NULL, "Printing JSON data failed"); if (opt_interactive) res = cJSON_Print (err_obj); res = cJSON_PrintUnformatted (err_obj); @@ -3228,7 +3231,7 @@ process_request (const char *request) if (!res) { /* Can't happen unless we created a broken error_object above */ - return strdup ("Bug: Fatal error in process request\n"); + return xtrystrdup ("Bug: Fatal error in process request\n"); } return res; } @@ -3626,7 +3629,7 @@ native_messaging_repl (void) } else /* Process request */ { - request[n] = '\0'; /* Esnure that request has an end */ + request[n] = '\0'; /* Ensure that request has an end */ if (opt_debug) log_debug ("request='%s'\n", request); xfree (response); commit f42cd70f18d53df47cc2d027bade736377d39b71 Author: Werner Koch Date: Thu Jul 19 09:50:30 2018 +0200 core: New interface gpgme_data_new_from_estream. * src/gpgme.h.in (gpgme_data_new_from_estream): New. * src/data-estream.c: New. * src/data.h (gpgme_data): New union member e_stream. -- The estream functions (gpgrt_fopen et al.) are any waypart of the required libgpg-error library and thus it makes sense to provide this convenience interface. Signed-off-by: Werner Koch diff --git a/NEWS b/NEWS index ae80642..20a80e8 100644 --- a/NEWS +++ b/NEWS @@ -7,13 +7,16 @@ Noteworthy changes in version 1.11.2 (unreleased) * Added context flag "auto-key-locate" to control the behavior of GPGME_KEYLIST_MODE_LOCATE. + * New data function to create a data object from an estream. + * Interface changes relative to the 1.11.1 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + gpgme_data_new_from_estream NEW. gpgme_decrypt_result_t EXTENDED: New field legacy_cipher_nomdc. gpgme_set_ctx_flag EXTENDED: New flag 'ignore-mdc-error'. GPGME_AUDITLOG_DEFAULT NEW. GPGME_AUDITLOG_DIAG NEW. - gpgme_set_ctx_flag EXTENDED: New flag 'auto-key-locate'. + gpgme_set_ctx_flag EXTENDED: New flag 'auto-key-locate'. cpp: DecryptionResult::sessionKey NEW. cpp: DecryptionResult::symkeyAlgo NEW. cpp: DecryptionResult::isLegacyCipherNoMDC New. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 38d3480..aff7240 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -1909,6 +1909,25 @@ data object was successfully created, and @code{GPG_ERR_ENOMEM} if not enough memory is available. @end deftypefun + at deftypefun gpgme_error_t gpgme_data_new_from_estream (@w{gpgme_data_t *@var{dh}}, @w{gpgrt_stream_t @var{stream}}) +The function @code{gpgme_data_new_from_estream} creates a new + at code{gpgme_data_t} object and uses the gpgrt stream @var{stream} to read +from (if used as an input data object) and write to (if used as an +output data object). + +When using the data object as an input buffer, the function might read +a bit more from the stream than is actually needed by the crypto +engine in the desired operation because of internal buffering. + +Note that GPGME assumes that the stream is in blocking mode. Errors +during I/O operations, except for EINTR, are usually fatal for crypto +operations. + +The function returns the error code @code{GPG_ERR_NO_ERROR} if the +data object was successfully created, and @code{GPG_ERR_ENOMEM} if not +enough memory is available. + at end deftypefun + @node Callback Based Data Buffers @subsection Callback Based Data Buffers diff --git a/src/Makefile.am b/src/Makefile.am index 0a196e0..1394c02 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -70,6 +70,7 @@ main_sources = \ parsetlv.c parsetlv.h \ mbox-util.c mbox-util.h \ data.h data.c data-fd.c data-stream.c data-mem.c data-user.c \ + data-estream.c \ data-compat.c data-identify.c \ signers.c sig-notation.c \ wait.c wait-global.c wait-private.c wait-user.c wait.h \ diff --git a/src/data-estream.c b/src/data-estream.c new file mode 100644 index 0000000..34f88a7 --- /dev/null +++ b/src/data-estream.c @@ -0,0 +1,99 @@ +/* data-stream.c - A stream based data object. + * Copyright (C) 2002, 2004, 2018 g10 Code GmbH + * + * This file is part of GPGME. + * + * GPGME 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. + * + * GPGME 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 + * Lesser 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 . + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#if HAVE_CONFIG_H +#include +#endif + +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#include "debug.h" +#include "data.h" + + +static gpgme_ssize_t +stream_es_read (gpgme_data_t dh, void *buffer, size_t size) +{ + size_t amt = gpgrt_fread (buffer, 1, size, dh->data.e_stream); + if (amt > 0) + return amt; + return gpgrt_ferror (dh->data.e_stream) ? -1 : 0; +} + + +static gpgme_ssize_t +stream_es_write (gpgme_data_t dh, const void *buffer, size_t size) +{ + size_t amt = gpgrt_fwrite (buffer, 1, size, dh->data.e_stream); + if (amt > 0) + return amt; + return gpgrt_ferror (dh->data.e_stream) ? -1 : 0; +} + + +static gpgme_off_t +stream_es_seek (gpgme_data_t dh, gpgme_off_t offset, int whence) +{ + int err; + + err = gpgrt_fseeko (dh->data.e_stream, offset, whence); + if (err) + return -1; + + return gpgrt_ftello (dh->data.e_stream); +} + + +static int +stream_es_get_fd (gpgme_data_t dh) +{ + gpgrt_fflush (dh->data.e_stream); + return gpgrt_fileno (dh->data.e_stream); +} + + +static struct _gpgme_data_cbs stream_es_cbs = + { + stream_es_read, + stream_es_write, + stream_es_seek, + NULL, + stream_es_get_fd + }; + + + +gpgme_error_t +gpgme_data_new_from_estream (gpgme_data_t *r_dh, gpgrt_stream_t stream) +{ + gpgme_error_t err; + TRACE_BEG1 (DEBUG_DATA, "gpgme_data_new_from_estream", r_dh, "estream=%p", + stream); + + err = _gpgme_data_new (r_dh, &stream_es_cbs); + if (err) + return TRACE_ERR (err); + + (*r_dh)->data.e_stream = stream; + return TRACE_SUC1 ("dh=%p", *r_dh); +} diff --git a/src/data.h b/src/data.h index 0a15b61..f12508b 100644 --- a/src/data.h +++ b/src/data.h @@ -100,6 +100,9 @@ struct gpgme_data /* For gpgme_data_new_from_stream. */ FILE *stream; + /* For gpgme_data_new_from_estream. */ + gpgrt_stream_t e_stream; + /* For gpgme_data_new_from_cbs. */ struct { diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 421199a..3596801 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -1180,6 +1180,8 @@ gpgme_error_t gpgme_data_new_from_cbs (gpgme_data_t *dh, gpgme_error_t gpgme_data_new_from_fd (gpgme_data_t *dh, int fd); gpgme_error_t gpgme_data_new_from_stream (gpgme_data_t *dh, FILE *stream); +gpgme_error_t gpgme_data_new_from_estream (gpgme_data_t *r_dh, + gpgrt_stream_t stream); /* Return the encoding attribute of the data buffer DH */ gpgme_data_encoding_t gpgme_data_get_encoding (gpgme_data_t dh); ----------------------------------------------------------------------- Summary of changes: NEWS | 5 ++- doc/gpgme.texi | 19 +++++++++++ src/Makefile.am | 1 + src/data-estream.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/data.h | 3 ++ src/gpgme-json.c | 13 ++++--- src/gpgme.h.in | 2 ++ 7 files changed, 136 insertions(+), 6 deletions(-) create mode 100644 src/data-estream.c hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 19 12:59:55 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Thu, 19 Jul 2018 12:59:55 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-102-g8168dfb Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 8168dfbeb12042a7f7b1bad918ef60df92bfd1a7 (commit) from af2c74d6c06a9fb08f7de15d41162d09f871a62e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 8168dfbeb12042a7f7b1bad918ef60df92bfd1a7 Author: Andre Heinecke Date: Thu Jul 19 12:58:49 2018 +0200 cpp: Print origin and last update for key/uid * lang/cpp/src/key.cpp: Print origin and last update in iostream operators. diff --git a/lang/cpp/src/key.cpp b/lang/cpp/src/key.cpp index 034286f..61b3eb7 100644 --- a/lang/cpp/src/key.cpp +++ b/lang/cpp/src/key.cpp @@ -1042,6 +1042,8 @@ std::ostream &operator<<(std::ostream &os, const UserID &uid) << "\n revoked: " << uid.isRevoked() << "\n invalid: " << uid.isInvalid() << "\n numsigs: " << uid.numSignatures() + << "\n origin: " << uid.origin() + << "\n updated: " << uid.lastUpdate() << "\n tofuinfo:\n" << uid.tofuInfo(); } return os << ')'; @@ -1060,6 +1062,8 @@ std::ostream &operator<<(std::ostream &os, const Key &key) << "\n canEncrypt: " << key.canEncrypt() << "\n canCertify: " << key.canCertify() << "\n canAuth: " << key.canAuthenticate() + << "\n origin: " << key.origin() + << "\n updated: " << key.lastUpdate() << "\n uids:\n"; const std::vector uids = key.userIDs(); std::copy(uids.begin(), uids.end(), ----------------------------------------------------------------------- Summary of changes: lang/cpp/src/key.cpp | 4 ++++ 1 file changed, 4 insertions(+) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 19 17:48:53 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 19 Jul 2018 17:48:53 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-103-g085cded Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 085cdeddef637cc057362fcbde13b0261b8699ec (commit) from 8168dfbeb12042a7f7b1bad918ef60df92bfd1a7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 085cdeddef637cc057362fcbde13b0261b8699ec Author: Werner Koch Date: Thu Jul 19 17:38:50 2018 +0200 core: Blank out the plaintext after decryption failure. * src/data.h (data_prop_t): New enum. (struct gpgme_data): Add field propidx. * src/data.c (property_t): New. (property_table, property_table_size, property_table_lock): New. (insert_into_property_table): New. (remove_from_property_table): New. (_gpgme_data_get_dserial): New. (_gpgme_data_set_prop): New. (_gpgme_data_get_prop): New. (_gpgme_data_new): Connect new object to property_table. (_gpgme_data_release): Remove from property_table. (gpgme_data_read): With DATA_PROP_BLANKOUT set don't fill the buffer. * src/data-mem.c (gpgme_data_release_and_get_mem): Likewise. * src/decrypt.c (struct op_data): Add field plaintext_dserial. (_gpgme_op_decrypt_init_result): Add arg plaintext and init new field. (_gpgme_decrypt_status_handler): Set DATA_PROP_BLANKOUT on decryption failure. (_gpgme_decrypt_start): Pass PLAIN to the init function. * src/decrypt-verify.c (decrypt_verify_start): Ditto. * configure.ac: Check for stdint.h and bail out if uint64_t is not available. -- This is a best effort feature to not output plaintext after a decryption failure (e.g. due to no or broken authenticated encryption). It always work when using a memory object and reading it after the decryption but it can't work reliable when the user is reading from the data object while the decryption process is still running. This is quite a large change because the data objects and the context objects are allowed to be owned by different threads. Thus a synchronization is needed and we do this with a global table of all data objects to which the context objects can do soft-linking via a unique data object serial number. Signed-off-by: Werner Koch diff --git a/configure.ac b/configure.ac index a1da1e3..fb43474 100644 --- a/configure.ac +++ b/configure.ac @@ -537,7 +537,7 @@ AM_CONDITIONAL(RUN_G13_TESTS, test "$run_g13_test" = "yes") # Checks for header files. -AC_CHECK_HEADERS_ONCE([locale.h sys/select.h sys/uio.h argp.h +AC_CHECK_HEADERS_ONCE([locale.h sys/select.h sys/uio.h argp.h stdint.h unistd.h sys/time.h sys/types.h sys/stat.h]) @@ -548,6 +548,15 @@ AC_SYS_LARGEFILE AC_TYPE_OFF_T AC_TYPE_UINTPTR_T +# We require uint64_t +if test "$ac_cv_header_stdint_h" != yes; then + AC_MSG_ERROR([[ +*** +*** No stdint.h and thus no uint64_t type. Can't build this library. +***]]) +fi + + # A simple compile time check in gpgme.h for GNU/Linux systems that # prevents a file offset bits mismatch between gpgme and the application. NEED__FILE_OFFSET_BITS=0 diff --git a/src/data-mem.c b/src/data-mem.c index a498b82..7569f7d 100644 --- a/src/data-mem.c +++ b/src/data-mem.c @@ -224,7 +224,10 @@ gpgme_data_new_from_mem (gpgme_data_t *r_dh, const char *buffer, char * gpgme_data_release_and_get_mem (gpgme_data_t dh, size_t *r_len) { + gpg_error_t err; char *str = NULL; + size_t len; + int blankout; TRACE_BEG1 (DEBUG_DATA, "gpgme_data_release_and_get_mem", dh, "r_len=%p", r_len); @@ -236,10 +239,22 @@ gpgme_data_release_and_get_mem (gpgme_data_t dh, size_t *r_len) return NULL; } + err = _gpgme_data_get_prop (dh, 0, DATA_PROP_BLANKOUT, &blankout); + if (err) + { + gpgme_data_release (dh); + TRACE_ERR (err); + return NULL; + } + str = dh->data.mem.buffer; + len = dh->data.mem.length; + if (blankout && len) + len = 1; + if (!str && dh->data.mem.orig_buffer) { - str = malloc (dh->data.mem.length); + str = malloc (len); if (!str) { int saved_err = gpg_error_from_syserror (); @@ -247,15 +262,22 @@ gpgme_data_release_and_get_mem (gpgme_data_t dh, size_t *r_len) TRACE_ERR (saved_err); return NULL; } - memcpy (str, dh->data.mem.orig_buffer, dh->data.mem.length); + if (blankout) + memset (str, 0, len); + else + memcpy (str, dh->data.mem.orig_buffer, len); } else - /* Prevent mem_release from releasing the buffer memory. We must - not fail from this point. */ - dh->data.mem.buffer = NULL; + { + if (blankout && len) + *str = 0; + /* Prevent mem_release from releasing the buffer memory. We + * must not fail from this point. */ + dh->data.mem.buffer = NULL; + } if (r_len) - *r_len = dh->data.mem.length; + *r_len = len; gpgme_data_release (dh); diff --git a/src/data.c b/src/data.c index 7ae5b32..e826f10 100644 --- a/src/data.c +++ b/src/data.c @@ -28,6 +28,7 @@ #endif #include #include +#include #include "gpgme.h" #include "data.h" @@ -36,10 +37,269 @@ #include "priv-io.h" #include "debug.h" + +/* The property table which has an entry for each active data object. + * The data object itself uses an index into this table and the table + * has a pointer back to the data object. All access to that table is + * controlled by the property_table_lock. + * + * We use a separate table instead of linking all data objects + * together for faster locating properties of the data object using + * the data objects serial number. We use 64 bit for the serial + * number which is good enough to create a new data object every + * nanosecond for more than 500 years. Thus no wrap around will ever + * happen. + */ +struct property_s +{ + gpgme_data_t dh; /* The data objcet or NULL if the slot is not used. */ + uint64_t dserial; /* The serial number of the data object. */ + struct { + unsigned int blankout : 1; /* Void the held data. */ + } flags; +}; +typedef struct property_s *property_t; + +static property_t property_table; +static unsigned int property_table_size; +DEFINE_STATIC_LOCK (property_table_lock); + + + +/* Insert the newly created data object DH into the property table and + * store the index of it at R_IDX. An error code is returned on error + * and the table is not changed. */ +static gpg_error_t +insert_into_property_table (gpgme_data_t dh, unsigned int *r_idx) +{ + static uint64_t last_dserial; + gpg_error_t err; + unsigned int idx; + + LOCK (property_table_lock); + if (!property_table) + { + property_table_size = 10; + property_table = calloc (property_table_size, sizeof *property_table); + if (!property_table) + { + err = gpg_error_from_syserror (); + goto leave; + } + } + + /* Find an empty slot. */ + for (idx = 0; idx < property_table_size; idx++) + if (!property_table[idx].dh) + break; + if (!(idx < property_table_size)) + { + /* No empty slot found. Enlarge the table. */ + property_t newtbl; + unsigned int newsize; + + newsize = property_table_size + 10; + if ((newsize * sizeof *property_table) + < (property_table_size * sizeof *property_table)) + { + err = gpg_error (GPG_ERR_ENOMEM); + goto leave; + } + newtbl = realloc (property_table, newsize * sizeof *property_table); + if (!newtbl) + { + err = gpg_error_from_syserror (); + goto leave; + } + property_table = newtbl; + for (idx = property_table_size; idx < newsize; idx++) + property_table[idx].dh = NULL; + idx = property_table_size; + property_table_size = newsize; + } + + /* Slot found. */ + property_table[idx].dh = dh; + property_table[idx].dserial = ++last_dserial; + *r_idx = idx; + err = 0; + + leave: + UNLOCK (property_table_lock); + return err; +} + + +/* Remove the data object at PROPIDX from the table. DH is only used + * for cross checking. */ +static void +remove_from_property_table (gpgme_data_t dh, unsigned int propidx) +{ + LOCK (property_table_lock); + assert (property_table); + assert (propidx < property_table_size); + assert (property_table[propidx].dh == dh); + property_table[propidx].dh = NULL; + UNLOCK (property_table_lock); +} + + +/* Return the data object's serial number for handle DH. This is a + * unique serial number for each created data object. */ +uint64_t +_gpgme_data_get_dserial (gpgme_data_t dh) +{ + uint64_t dserial; + unsigned int idx; + + if (!dh) + return 0; + + idx = dh->propidx; + LOCK (property_table_lock); + assert (property_table); + assert (idx < property_table_size); + assert (property_table[idx].dh == dh); + dserial = property_table[idx].dserial; + UNLOCK (property_table_lock); + + return dserial; +} + + +/* Set an internal property of a data object. The data object may + * either be identified by the usual DH or by using the data serial + * number DSERIAL. */ +gpg_error_t +_gpgme_data_set_prop (gpgme_data_t dh, uint64_t dserial, + data_prop_t name, int value) +{ + gpg_error_t err = 0; + int idx; + TRACE_BEG3 (DEBUG_DATA, "gpgme_data_set_prop", dh, + "dserial=%llu %lu=%d", + (unsigned long long)dserial, + (unsigned long)name, value); + + LOCK (property_table_lock); + if ((!dh && !dserial) || (dh && dserial)) + { + err = gpg_error (GPG_ERR_INV_VALUE); + goto leave; + } + if (dh) /* Lookup via handle. */ + { + idx = dh->propidx; + assert (property_table); + assert (idx < property_table_size); + assert (property_table[idx].dh == dh); + } + else /* Lookup via DSERIAL. */ + { + if (!property_table) + { + err = gpg_error (GPG_ERR_NOT_FOUND); + goto leave; + } + for (idx = 0; idx < property_table_size; idx++) + if (property_table[idx].dh && property_table[idx].dserial == dserial) + break; + if (!(idx < property_table_size)) + { + err = gpg_error (GPG_ERR_NOT_FOUND); + goto leave; + } + } + + switch (name) + { + case DATA_PROP_NONE: /* Nothing to to do. */ + break; + case DATA_PROP_BLANKOUT: + property_table[idx].flags.blankout = !!value; + break; + + default: + err = gpg_error (GPG_ERR_UNKNOWN_NAME); + break; + } + + leave: + UNLOCK (property_table_lock); + return TRACE_ERR (err); +} + + +/* Get an internal property of a data object. This is the counter + * part to _gpgme_data_set_property. The value of the property is + * stored at R_VALUE. On error 0 is stored at R_VALUE. */ +gpg_error_t +_gpgme_data_get_prop (gpgme_data_t dh, uint64_t dserial, + data_prop_t name, int *r_value) +{ + gpg_error_t err = 0; + int idx; + TRACE_BEG2 (DEBUG_DATA, "gpgme_data_get_prop", dh, + "dserial=%llu %lu", + (unsigned long long)dserial, + (unsigned long)name); + + *r_value = 0; + + LOCK (property_table_lock); + if ((!dh && !dserial) || (dh && dserial)) + { + err = gpg_error (GPG_ERR_INV_VALUE); + goto leave; + } + if (dh) /* Lookup via handle. */ + { + idx = dh->propidx; + assert (property_table); + assert (idx < property_table_size); + assert (property_table[idx].dh == dh); + } + else /* Lookup via DSERIAL. */ + { + if (!property_table) + { + err = gpg_error (GPG_ERR_NOT_FOUND); + goto leave; + } + for (idx = 0; idx < property_table_size; idx++) + if (property_table[idx].dh && property_table[idx].dserial == dserial) + break; + if (!(idx < property_table_size)) + { + err = gpg_error (GPG_ERR_NOT_FOUND); + goto leave; + } + } + + switch (name) + { + case DATA_PROP_NONE: /* Nothing to to do. */ + break; + case DATA_PROP_BLANKOUT: + *r_value = property_table[idx].flags.blankout; + break; + + default: + err = gpg_error (GPG_ERR_UNKNOWN_NAME); + break; + } + + leave: + UNLOCK (property_table_lock); + return TRACE_ERR (err); +} + + gpgme_error_t _gpgme_data_new (gpgme_data_t *r_dh, struct _gpgme_data_cbs *cbs) { + gpgme_error_t err; gpgme_data_t dh; if (!r_dh) @@ -56,6 +316,13 @@ _gpgme_data_new (gpgme_data_t *r_dh, struct _gpgme_data_cbs *cbs) dh->cbs = cbs; + err = insert_into_property_table (dh, &dh->propidx); + if (err) + { + free (dh); + return err; + } + *r_dh = dh; return 0; } @@ -67,11 +334,13 @@ _gpgme_data_release (gpgme_data_t dh) if (!dh) return; + remove_from_property_table (dh, dh->propidx); if (dh->file_name) free (dh->file_name); free (dh); } + /* Read up to SIZE bytes into buffer BUFFER from the data object with the handle DH. Return the number of characters read, 0 on EOF and @@ -80,6 +349,7 @@ gpgme_ssize_t gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size) { gpgme_ssize_t res; + int blankout; TRACE_BEG2 (DEBUG_DATA, "gpgme_data_read", dh, "buffer=%p, size=%u", buffer, size); @@ -93,9 +363,16 @@ gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size) gpg_err_set_errno (ENOSYS); return TRACE_SYSRES (-1); } - do - res = (*dh->cbs->read) (dh, buffer, size); - while (res < 0 && errno == EINTR); + + if (_gpgme_data_get_prop (dh, 0, DATA_PROP_BLANKOUT, &blankout) + || blankout) + res = 0; + else + { + do + res = (*dh->cbs->read) (dh, buffer, size); + while (res < 0 && errno == EINTR); + } return TRACE_SYSRES (res); } diff --git a/src/data.h b/src/data.h index f12508b..692eb9a 100644 --- a/src/data.h +++ b/src/data.h @@ -29,6 +29,7 @@ # include #endif #include +#include #include "gpgme.h" @@ -73,6 +74,7 @@ struct gpgme_data { struct _gpgme_data_cbs *cbs; gpgme_data_encoding_t encoding; + unsigned int propidx; /* Index into the property table. */ #ifdef PIPE_BUF #define BUFFER_SIZE PIPE_BUF @@ -89,7 +91,7 @@ struct gpgme_data /* File name of the data object. */ char *file_name; - /* Hint on the to be expected toatl size of the data. */ + /* Hint on the to be expected total size of the data. */ gpgme_off_t size_hint; union @@ -130,7 +132,28 @@ struct gpgme_data } data; }; + +/* The data property types. */ +typedef enum + { + DATA_PROP_NONE = 0, /* Dummy property. */ + DATA_PROP_BLANKOUT /* Do not return the held data. */ + } data_prop_t; + + +/* Return the data object's serial number for handle DH. */ +uint64_t _gpgme_data_get_dserial (gpgme_data_t dh); + +/* Set an internal property of a data object. */ +gpg_error_t _gpgme_data_set_prop (gpgme_data_t dh, uint64_t dserial, + data_prop_t name, int value); + +/* Get an internal property of a data object. */ +gpg_error_t _gpgme_data_get_prop (gpgme_data_t dh, uint64_t dserial, + data_prop_t name, int *r_value); + +/* Create a new data object. */ gpgme_error_t _gpgme_data_new (gpgme_data_t *r_dh, struct _gpgme_data_cbs *cbs); @@ -143,4 +166,5 @@ int _gpgme_data_get_fd (gpgme_data_t dh); /* Get the size-hint value for DH or 0 if not available. */ gpgme_off_t _gpgme_data_get_size_hint (gpgme_data_t dh); + #endif /* DATA_H */ diff --git a/src/decrypt-verify.c b/src/decrypt-verify.c index 1bd81c3..224edc1 100644 --- a/src/decrypt-verify.c +++ b/src/decrypt-verify.c @@ -58,7 +58,7 @@ decrypt_verify_start (gpgme_ctx_t ctx, int synchronous, if (err) return err; - err = _gpgme_op_decrypt_init_result (ctx); + err = _gpgme_op_decrypt_init_result (ctx, plain); if (err) return err; diff --git a/src/decrypt.c b/src/decrypt.c index f5b93d7..b51603a 100644 --- a/src/decrypt.c +++ b/src/decrypt.c @@ -32,7 +32,7 @@ #include "util.h" #include "context.h" #include "ops.h" - +#include "data.h" typedef struct @@ -69,6 +69,9 @@ typedef struct This makes appending new invalid signers painless while preserving the order. */ gpgme_recipient_t *last_recipient_p; + + /* The data object serial number of the plaintext. */ + uint64_t plaintext_dserial; } *op_data_t; @@ -419,6 +422,14 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, case GPGME_STATUS_DECRYPTION_FAILED: opd->failed = 1; + /* Tell the data object that it shall not return any data. We + * use the serial number because the data object may be owned by + * another thread. We also don't check for an error because it + * is possible that the data object has already been destroyed + * and we are then not interested in returning an error. */ + if (!ctx->ignore_mdc_error) + _gpgme_data_set_prop (NULL, opd->plaintext_dserial, + DATA_PROP_BLANKOUT, 1); break; case GPGME_STATUS_ERROR: @@ -508,7 +519,7 @@ decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args) gpgme_error_t -_gpgme_op_decrypt_init_result (gpgme_ctx_t ctx) +_gpgme_op_decrypt_init_result (gpgme_ctx_t ctx, gpgme_data_t plaintext) { gpgme_error_t err; void *hook; @@ -521,6 +532,7 @@ _gpgme_op_decrypt_init_result (gpgme_ctx_t ctx) return err; opd->last_recipient_p = &opd->result.recipients; + opd->plaintext_dserial = _gpgme_data_get_dserial (plaintext); return 0; } @@ -538,7 +550,7 @@ _gpgme_decrypt_start (gpgme_ctx_t ctx, int synchronous, if (err) return err; - err = _gpgme_op_decrypt_init_result (ctx); + err = _gpgme_op_decrypt_init_result (ctx, plain); if (err) return err; diff --git a/src/ops.h b/src/ops.h index 5955454..3b9728d 100644 --- a/src/ops.h +++ b/src/ops.h @@ -85,7 +85,8 @@ gpgme_error_t _gpgme_verify_status_handler (void *priv, /* From decrypt.c. */ -gpgme_error_t _gpgme_op_decrypt_init_result (gpgme_ctx_t ctx); +gpgme_error_t _gpgme_op_decrypt_init_result (gpgme_ctx_t ctx, + gpgme_data_t plaintext); gpgme_error_t _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args); ----------------------------------------------------------------------- Summary of changes: configure.ac | 11 +- src/data-mem.c | 34 +++++-- src/data.c | 283 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/data.h | 26 ++++- src/decrypt-verify.c | 2 +- src/decrypt.c | 18 +++- src/ops.h | 3 +- 7 files changed, 361 insertions(+), 16 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 19 20:47:17 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Thu, 19 Jul 2018 20:47:17 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-104-g5ef492c Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 5ef492c5635ae1677eed6f439a75a86a99dbbe18 (commit) from 085cdeddef637cc057362fcbde13b0261b8699ec (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 5ef492c5635ae1677eed6f439a75a86a99dbbe18 Author: Werner Koch Date: Thu Jul 19 20:38:21 2018 +0200 core: Clear all flags for a new data property. * src/data.c (PROPERTY_TABLE_ALLOCATION_CHUNK): New. (insert_into_property_table): Use it here. Clear all flags. -- Fixes-commit: 085cdeddef637cc057362fcbde13b0261b8699ec Signed-off-by: Werner Koch diff --git a/src/data.c b/src/data.c index e826f10..1df6b0a 100644 --- a/src/data.c +++ b/src/data.c @@ -63,6 +63,7 @@ typedef struct property_s *property_t; static property_t property_table; static unsigned int property_table_size; DEFINE_STATIC_LOCK (property_table_lock); +#define PROPERTY_TABLE_ALLOCATION_CHUNK 32 @@ -79,7 +80,7 @@ insert_into_property_table (gpgme_data_t dh, unsigned int *r_idx) LOCK (property_table_lock); if (!property_table) { - property_table_size = 10; + property_table_size = PROPERTY_TABLE_ALLOCATION_CHUNK; property_table = calloc (property_table_size, sizeof *property_table); if (!property_table) { @@ -98,7 +99,7 @@ insert_into_property_table (gpgme_data_t dh, unsigned int *r_idx) property_t newtbl; unsigned int newsize; - newsize = property_table_size + 10; + newsize = property_table_size + PROPERTY_TABLE_ALLOCATION_CHUNK;; if ((newsize * sizeof *property_table) < (property_table_size * sizeof *property_table)) { @@ -121,6 +122,7 @@ insert_into_property_table (gpgme_data_t dh, unsigned int *r_idx) /* Slot found. */ property_table[idx].dh = dh; property_table[idx].dserial = ++last_dserial; + memset (&property_table[idx].flags, 0, sizeof property_table[idx].flags); *r_idx = idx; err = 0; ----------------------------------------------------------------------- Summary of changes: src/data.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Fri Jul 20 10:50:51 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Fri, 20 Jul 2018 10:50:51 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-79-g35e6637 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via 35e663754f7d407adf4ae6864f41da288f11ecb9 (commit) via 3a0fdfd1cb67db0282f74b327ee303685b7b6f1d (commit) via ff589bd30f79b606566f68446b0f2b5f3641e17b (commit) via 3f51209f207fc0df13ff42db57429b8c6542db9b (commit) via a74cfd9861cecc8bdb2226b2dd280bf862697d2d (commit) via 909a57ff02cd399878d0219bd10ab25177e4f2bc (commit) via 5959ec68f8ae30e3085d5a180db39d7ca4d48817 (commit) via af4626b1fdcebbf9fe36d4aae9c664df7780099d (commit) via 2e63ea41583fc7cfb3f7e1442f6d9c6a846d6d16 (commit) via 74c6f5d78ee6bf31fc70ef5ad0b6cd3b3656a0aa (commit) via fe5ce6b8faf4503f8996f4bd10afdaa8b9aaba0c (commit) via 05c70803c61420cc61f566b577117522ead3f1a4 (commit) from 5e2078d4f6686823d9a6c7a69490ccf02144ce4c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 35e663754f7d407adf4ae6864f41da288f11ecb9 Author: Andre Heinecke Date: Fri Jul 20 10:48:02 2018 +0200 Fix big reference leak of cipherstream / message * src/mail.cpp (get_attachment_stream_o): Release message and mapi_attachment after obtaining the stream. -- This is a big leak. It probably means that Outlook kept the original Message fully in the memory. For this the memdbg interface might already be worth it. diff --git a/src/mail.cpp b/src/mail.cpp index 9192b4a..38ee1d0 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -451,8 +451,9 @@ get_attachment_stream_o (LPDISPATCH mailitem, int pos) SRCNAME, __func__); return NULL; } - hr = message->OpenProperty (PR_BODY_A, &IID_IStream, 0, 0, - (LPUNKNOWN*)&stream); + hr = gpgol_openProperty (message, PR_BODY_A, &IID_IStream, 0, 0, + (LPUNKNOWN*)&stream); + gpgol_release (message); if (hr) { log_debug ("%s:%s: OpenProperty failed: hr=%#lx", @@ -473,13 +474,15 @@ get_attachment_stream_o (LPDISPATCH mailitem, int pos) SRCNAME, __func__, attachment); return NULL; } - if (FAILED (mapi_attachment->OpenProperty (PR_ATTACH_DATA_BIN, &IID_IStream, - 0, MAPI_MODIFY, (LPUNKNOWN*) &stream))) + if (FAILED (gpgol_openProperty (mapi_attachment, PR_ATTACH_DATA_BIN, + &IID_IStream, 0, MAPI_MODIFY, + (LPUNKNOWN*) &stream))) { log_debug ("%s:%s: Failed to open stream for mapi_attachment: %p", SRCNAME, __func__, mapi_attachment); gpgol_release (mapi_attachment); } + gpgol_release (mapi_attachment); return stream; } commit 3a0fdfd1cb67db0282f74b327ee303685b7b6f1d Author: Andre Heinecke Date: Fri Jul 20 10:46:13 2018 +0200 Improve memdbg name output * src/memdbg.cpp (register_name): Handle name changes. (memdbg_addRef): Handle name change. diff --git a/src/memdbg.cpp b/src/memdbg.cpp index cd506dc..088767f 100644 --- a/src/memdbg.cpp +++ b/src/memdbg.cpp @@ -42,28 +42,53 @@ GPGRT_LOCK_DEFINE (memdbg_log); # include "oomhelp.h" #endif -static void +/* Returns true on a name change */ +static bool register_name (void *obj) { #ifdef HAVE_W32_SYSTEM - auto it = olNames.find (obj); - - if (it != olNames.end()) - { - return; - } char *name = get_object_name ((LPUNKNOWN)obj); + if (!name) { - return; + auto it = olNames.find (obj); + if (it != olNames.end()) + { + if (it->second != "unknown") + { + log_debug ("%s:%s Ptr %p name change from %s to unknown", + SRCNAME, __func__, obj, it->second.c_str()); + it->second = "unknown"; + return true; + } + } + return false; } + std::string sName = name; - olNames.insert (std::make_pair (obj, sName)); xfree (name); + + auto it = olNames.find (obj); + if (it != olNames.end()) + { + if (it->second != sName) + { + log_debug ("%s:%s Ptr %p name change from %s to %s", + SRCNAME, __func__, obj, it->second.c_str(), + sName.c_str()); + it->second = sName; + return true; + } + } + else + { + olNames.insert (std::make_pair (obj, sName)); + } #else (void) obj; #endif + return false; } void @@ -83,7 +108,11 @@ memdbg_addRef (void *obj) if (it == olObjs.end()) { it = olObjs.insert (std::make_pair (obj, 0)).first; - register_name (obj); + } + if (register_name (obj) && it->second) + { + log_error ("%s:%s Name change without null ref on %p!", + SRCNAME, __func__, obj); } it->second++; commit ff589bd30f79b606566f68446b0f2b5f3641e17b Author: Andre Heinecke Date: Fri Jul 20 10:45:00 2018 +0200 Change an error to debug * src/mail.cpp (Mail::installFolderEventHandler_o): Don't print the success message as error. diff --git a/src/mail.cpp b/src/mail.cpp index f2f99f4..9192b4a 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -3415,7 +3415,7 @@ Mail::installFolderEventHandler_o() if (s_folder_events_map.find (strPath) == s_folder_events_map.end()) { - log_error ("%s:%s: Install folder events watcher for %s.", + log_debug ("%s:%s: Install folder events watcher for %s.", SRCNAME, __func__, strPath.c_str()); const auto sink = install_FolderEvents_sink (folder); s_folder_events_map.insert (std::make_pair (strPath, sink)); commit 3f51209f207fc0df13ff42db57429b8c6542db9b Author: Andre Heinecke Date: Fri Jul 20 10:43:02 2018 +0200 Unref application unload / shutdown * src/gpgoladdin.cpp (GpgolAddin::shutdown): Release application. -- Minor and should not have been a problem. diff --git a/src/gpgoladdin.cpp b/src/gpgoladdin.cpp index fa18259..cf75cc1 100644 --- a/src/gpgoladdin.cpp +++ b/src/gpgoladdin.cpp @@ -1164,6 +1164,9 @@ GpgolAddin::shutdown () MB_ICONINFORMATION|MB_OK); } m_shutdown = true; + + gpgol_release (m_application); + m_application = nullptr; } void commit a74cfd9861cecc8bdb2226b2dd280bf862697d2d Author: Andre Heinecke Date: Fri Jul 20 10:40:40 2018 +0200 Fix reference error on Explorer / Explorers object * src/gpgoladdin.cpp (install_explorer_sinks): Release explorer and explorers after installing the sinks. -- The sinks handle the ref counting by themself. The reference leak should be not a real problem because the sinks keep them anyway until the end of the program. diff --git a/src/gpgoladdin.cpp b/src/gpgoladdin.cpp index 31eb440..fa18259 100644 --- a/src/gpgoladdin.cpp +++ b/src/gpgoladdin.cpp @@ -461,9 +461,13 @@ install_explorer_sinks (LPDISPATCH application) SRCNAME, __func__, sink, i); GpgolAddin::get_instance ()->registerExplorerSink (sink); } + gpgol_release (explorer); } /* Now install the event sink to handle new explorers */ - return install_ExplorersEvents_sink (explorers); + LPDISPATCH ret = install_ExplorersEvents_sink (explorers); + gpgol_release (explorers); + + return ret; } static DWORD WINAPI commit 909a57ff02cd399878d0219bd10ab25177e4f2bc Author: Andre Heinecke Date: Fri Jul 20 10:34:00 2018 +0200 Add memdbg handling for MAPI * src/gpgoladdin.cpp (GpgolAddin::OnConnection): Ref application. * src/mapihelp.cpp: Replace OpenProperty by gpgol_openProperty. memdbg_addRef for some MAPI functions that return an object. * src/mimemaker.cpp: Replace OpenProperty by gpgol_openProperty. * src/mlang-charset.cpp (ansi_charset_to_utf8): Mark multilang as reffed. * src/olflange.cpp (install_forms): Mark formcontainer as reffed. * src/oomhelp.cpp, src/oomhelp.h (gpgol_queryInterface): New. (get_oom_iunknown): Add ref. (get_oom_base_message_from_mapi): Add ref. * src/ribbon-callbacks.cpp (getIcon): Add ref on stream and change it to be automatically freed as we don't free it. diff --git a/src/gpgoladdin.cpp b/src/gpgoladdin.cpp index 0a0fe10..31eb440 100644 --- a/src/gpgoladdin.cpp +++ b/src/gpgoladdin.cpp @@ -319,6 +319,7 @@ GpgolAddin::OnConnection (LPDISPATCH Application, ext_ConnectMode ConnectMode, can_unload = false; m_application = Application; m_application->AddRef(); + memdbg_addRef (m_application); m_addin = AddInInst; version = get_oom_string (Application, "Version"); diff --git a/src/mapihelp.cpp b/src/mapihelp.cpp index 6d2c04f..6956e43 100644 --- a/src/mapihelp.cpp +++ b/src/mapihelp.cpp @@ -459,7 +459,7 @@ mapi_get_header (LPMESSAGE message) if (!message) return ret; - hr = message->OpenProperty (PR_TRANSPORT_MESSAGE_HEADERS_A, &IID_IStream, 0, 0, + hr = gpgol_openProperty (message, PR_TRANSPORT_MESSAGE_HEADERS_A, &IID_IStream, 0, 0, (LPUNKNOWN*)&stream); if (hr) { @@ -501,7 +501,7 @@ mapi_get_body_as_stream (LPMESSAGE message) /* The store knows about the Internet Charset Body property, thus try to get the body from this property if it exists. */ - hr = message->OpenProperty (tag, &IID_IStream, 0, 0, + hr = gpgol_openProperty (message, tag, &IID_IStream, 0, 0, (LPUNKNOWN*)&stream); if (!hr) return stream; @@ -514,7 +514,7 @@ mapi_get_body_as_stream (LPMESSAGE message) need to implement some kind of stream filter to translated to utf-8 or read everyting into a memory buffer and [provide an istream from that memory buffer. */ - hr = message->OpenProperty (PR_BODY_A, &IID_IStream, 0, 0, + hr = gpgol_openProperty (message, PR_BODY_A, &IID_IStream, 0, 0, (LPUNKNOWN*)&stream); if (hr) { @@ -567,7 +567,7 @@ mapi_get_body (LPMESSAGE message, size_t *r_nbytes) } else /* Message is large; use an IStream to read it. */ { - hr = message->OpenProperty (PR_BODY, &IID_IStream, 0, 0, + hr = gpgol_openProperty (message, PR_BODY, &IID_IStream, 0, 0, (LPUNKNOWN*)&stream); if (hr) { @@ -656,7 +656,7 @@ get_msgcls_from_pgp_lines (LPMESSAGE message, bool *r_nobody = nullptr) { log_debug ("%s:%s: Failed to get body ASCII stream.", SRCNAME, __func__); - hr = message->OpenProperty (PR_BODY_W, &IID_IStream, 0, 0, + hr = gpgol_openProperty (message, PR_BODY_W, &IID_IStream, 0, 0, (LPUNKNOWN*)&stream); if (hr) { @@ -856,7 +856,7 @@ is_really_cms_encrypted (LPMESSAGE message) goto leave; } - hr = att->OpenProperty (PR_ATTACH_DATA_BIN, &IID_IStream, + hr = gpgol_openProperty (att, PR_ATTACH_DATA_BIN, &IID_IStream, 0, 0, (LPUNKNOWN*) &stream); if (FAILED (hr)) { @@ -2296,6 +2296,7 @@ mapi_create_attach_table (LPMESSAGE message, int fast) /* Open the attachment table. */ hr = message->GetAttachmentTable (0, &mapitable); + memdbg_addRef (mapitable); if (FAILED (hr)) { log_debug ("%s:%s: GetAttachmentTable failed: hr=%#lx", @@ -2344,7 +2345,8 @@ mapi_create_attach_table (LPMESSAGE message, int fast) table[pos].mapipos = mapirows->aRow[pos].lpProps[0].Value.l; hr = message->OpenAttach (table[pos].mapipos, NULL, - MAPI_BEST_ACCESS, &att); + MAPI_BEST_ACCESS, &att); + memdbg_addRef (att); if (FAILED (hr)) { log_error ("%s:%s: can't open attachment %d (%d): hr=%#lx", @@ -2455,7 +2457,7 @@ mapi_get_attach_as_stream (LPMESSAGE message, mapi_attach_item_t *item, return NULL; } - hr = att->OpenProperty (PR_ATTACH_DATA_BIN, &IID_IStream, + hr = gpgol_openProperty (att, PR_ATTACH_DATA_BIN, &IID_IStream, 0, 0, (LPUNKNOWN*) &stream); if (FAILED (hr)) { @@ -2489,7 +2491,7 @@ attach_to_buffer (LPATTACH att, size_t *r_nbytes) ULONG nread; char *buffer; - hr = att->OpenProperty (PR_ATTACH_DATA_BIN, &IID_IStream, + hr = gpgol_openProperty (att, PR_ATTACH_DATA_BIN, &IID_IStream, 0, 0, (LPUNKNOWN*) &stream); if (FAILED (hr)) { @@ -3495,7 +3497,7 @@ mapi_attachment_to_body (LPMESSAGE message, mapi_attach_item_t *item) goto leave; } - hr = att->OpenProperty (PR_ATTACH_DATA_BIN, &IID_IStream, + hr = gpgol_openProperty (att, PR_ATTACH_DATA_BIN, &IID_IStream, 0, 0, (LPUNKNOWN*) &instream); if (FAILED (hr)) { @@ -3506,7 +3508,7 @@ mapi_attachment_to_body (LPMESSAGE message, mapi_attach_item_t *item) punk = (LPUNKNOWN)outstream; - hr = message->OpenProperty (PR_BODY_A, &IID_IStream, 0, + hr = gpgol_openProperty (message, PR_BODY_A, &IID_IStream, 0, MAPI_CREATE|MAPI_MODIFY, &punk); if (FAILED (hr)) { @@ -3618,7 +3620,7 @@ mapi_body_to_attachment (LPMESSAGE message) } punk = (LPUNKNOWN)outstream; - hr = newatt->OpenProperty (PR_ATTACH_DATA_BIN, &IID_IStream, 0, + hr = gpgol_openProperty (newatt, PR_ATTACH_DATA_BIN, &IID_IStream, 0, MAPI_CREATE|MAPI_MODIFY, &punk); if (FAILED (hr)) { @@ -3728,6 +3730,7 @@ mapi_mark_or_create_moss_attach (LPMESSAGE message, msgtype_t msgtype) SRCNAME, __func__, item->mapipos); return -1; } + memdbg_addRef (att); if (!mapi_test_attach_hidden (att)) { mapi_set_attach_hidden (att); diff --git a/src/mimemaker.cpp b/src/mimemaker.cpp index b1dfc31..29dcb3c 100644 --- a/src/mimemaker.cpp +++ b/src/mimemaker.cpp @@ -214,7 +214,7 @@ create_mapi_attachment (LPMESSAGE message, sink_t sink, } punk = NULL; - hr = att->OpenProperty(PR_ATTACH_DATA_BIN, &IID_IStream, 0, + hr = gpgol_openProperty (att, PR_ATTACH_DATA_BIN, &IID_IStream, 0, (MAPI_CREATE|MAPI_MODIFY), &punk); if (FAILED (hr)) { diff --git a/src/mlang-charset.cpp b/src/mlang-charset.cpp index 934c1e3..eb4cc85 100644 --- a/src/mlang-charset.cpp +++ b/src/mlang-charset.cpp @@ -53,6 +53,7 @@ char *ansi_charset_to_utf8 (const char *charset, const char *input, CoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, IID_IMultiLanguage, (void**)&multilang); + memdbg_addRef (multilang); if (!multilang) { diff --git a/src/olflange.cpp b/src/olflange.cpp index 3b25340..f1dd3c3 100644 --- a/src/olflange.cpp +++ b/src/olflange.cpp @@ -393,6 +393,7 @@ install_forms (void) SRCNAME, __func__); return; } + memdbg_addRef (formcontainer); datadir = get_data_dir (); if (!datadir) diff --git a/src/oomhelp.cpp b/src/oomhelp.cpp index 694ef59..2da1703 100644 --- a/src/oomhelp.cpp +++ b/src/oomhelp.cpp @@ -44,6 +44,22 @@ gpgol_queryInterface (LPUNKNOWN pObj, REFIID riid, LPVOID FAR *ppvObj) return ret; } +HRESULT +gpgol_openProperty (LPMAPIPROP obj, ULONG ulPropTag, LPCIID lpiid, + ULONG ulInterfaceOptions, ULONG ulFlags, + LPUNKNOWN FAR * lppUnk) +{ + HRESULT ret = obj->OpenProperty (ulPropTag, lpiid, + ulInterfaceOptions, ulFlags, + lppUnk); + if ((opt.enable_debug & DBG_OOM_EXTRA) && *lppUnk) + { + memdbg_addRef (*lppUnk); + log_debug ("%s:%s: OpenProperty on %p prop %lx result %p", + SRCNAME, __func__, obj, ulPropTag, *lppUnk); + } + return ret; +} /* Return a malloced string with the utf-8 encoded name of the object or NULL if not available. */ char * @@ -712,7 +728,10 @@ get_oom_iunknown (LPDISPATCH pDisp, const char *name) log_debug ("%s:%s: Property `%s' is not of class IUnknown (vt=%d)", SRCNAME, __func__, name, rVariant.vt); else - return rVariant.punkVal; + { + memdbg_addRef (rVariant.punkVal); + return rVariant.punkVal; + } VariantClear (&rVariant); } @@ -1555,6 +1574,7 @@ get_oom_base_message_from_mapi (LPDISPATCH mapi_message) log_oom_extra("%s:%s: About to call GetBaseMessage.", SRCNAME, __func__); hr = secureMessage->GetBaseMessage (&message); + memdbg_addRef (message); gpgol_release (secureMessage); if (hr != S_OK) { diff --git a/src/oomhelp.h b/src/oomhelp.h index 1991bee..3a94579 100644 --- a/src/oomhelp.h +++ b/src/oomhelp.h @@ -372,4 +372,8 @@ char *get_sender_SendUsingAccount (LPDISPATCH mailitem, bool *r_is_GSuite); /* memtracing query interface */ HRESULT gpgol_queryInterface (LPUNKNOWN pObj, REFIID riid, LPVOID FAR *ppvObj); + +HRESULT gpgol_openProperty (LPMAPIPROP obj, ULONG ulPropTag, LPCIID lpiid, + ULONG ulInterfaceOptions, ULONG ulFlags, + LPUNKNOWN FAR * lppUnk); #endif /*OOMHELP_H*/ diff --git a/src/ribbon-callbacks.cpp b/src/ribbon-callbacks.cpp index e31d208..9ba0796 100644 --- a/src/ribbon-callbacks.cpp +++ b/src/ribbon-callbacks.cpp @@ -134,8 +134,9 @@ getIcon (int id, VARIANT* result) IStream* pStream = NULL; CopyMemory (pBuffer, pResourceData, imageSize); - if (CreateStreamOnHGlobal (hBuffer, FALSE, &pStream) == S_OK) + if (CreateStreamOnHGlobal (hBuffer, TRUE, &pStream) == S_OK) { + memdbg_addRef (pStream); pbitmap = Gdiplus::Bitmap::FromStream (pStream); gpgol_release (pStream); if (!pbitmap || pbitmap->GetHBITMAP (0, &pdesc.bmp.hbitmap)) commit 5959ec68f8ae30e3085d5a180db39d7ca4d48817 Author: Andre Heinecke Date: Fri Jul 20 10:30:23 2018 +0200 Improve GpgolAddin debug output * src/gpgoladdin.cpp (DllCanUnloadNow): Trace call. (GpgolRibbonExtender::~GpgolRibbonExtender): Dump memory map. (GpgolAddinFactory::~GpgolAddinFactory): Debug dtor. diff --git a/src/gpgoladdin.cpp b/src/gpgoladdin.cpp index 220602b..0a0fe10 100644 --- a/src/gpgoladdin.cpp +++ b/src/gpgoladdin.cpp @@ -103,6 +103,7 @@ STDAPI DllCanUnloadNow() unload the Library. Any callbacks will become invalid. So we _only_ say it's ok to unload if we were disconnected. For the epic story behind the next line see GnuPG-Bug-Id 1837 */ + TRACEPOINT; return can_unload ? S_OK : S_FALSE; } @@ -154,6 +155,11 @@ STDMETHODIMP GpgolAddinFactory::CreateInstance (LPUNKNOWN punk, REFIID riid, return hr; } +GpgolAddinFactory::~GpgolAddinFactory() +{ + log_debug ("%s:%s: Object deleted\n", SRCNAME, __func__); +} + /* GpgolAddin definition */ @@ -577,7 +583,7 @@ GpgolRibbonExtender::~GpgolRibbonExtender (void) { log_debug ("%s:%s: cleaning up GpgolRibbonExtender object;", SRCNAME, __func__); - log_debug ("%s:%s: Object deleted\n", SRCNAME, __func__); + memdbg_dump (); } STDMETHODIMP diff --git a/src/gpgoladdin.h b/src/gpgoladdin.h index 05c23c0..e2ae977 100644 --- a/src/gpgoladdin.h +++ b/src/gpgoladdin.h @@ -232,7 +232,7 @@ class GpgolAddinFactory: public IClassFactory { public: GpgolAddinFactory(): m_lRef(0){} - virtual ~GpgolAddinFactory(){} + virtual ~GpgolAddinFactory(); STDMETHODIMP QueryInterface (REFIID riid, LPVOID* ppvObj); inline STDMETHODIMP_(ULONG) AddRef() { ++m_lRef; return m_lRef; }; commit af4626b1fdcebbf9fe36d4aae9c664df7780099d Author: Andre Heinecke Date: Fri Jul 20 10:28:42 2018 +0200 Don't export DllCanUnloadNow at all * src/gpgol.def (DllCanUnloadNow): Don't export. -- We don't want to be unloaded by com cleanup. And while we should have returned false always I saw one crash immediately after a Dll can unload now. diff --git a/src/gpgol.def b/src/gpgol.def index 40ba133..603716e 100644 --- a/src/gpgol.def +++ b/src/gpgol.def @@ -5,6 +5,5 @@ EXPORTS DllRegisterServer = DllRegisterServer at 0 @1 PRIVATE DllUnregisterServer = DllUnregisterServer at 0 @2 PRIVATE DllGetClassObject = DllGetClassObject at 12 @3 PRIVATE - DllCanUnloadNow = DllCanUnloadNow at 0 @4 PRIVATE gpgol_check_version = gpgol_check_version at 4 @11 commit 2e63ea41583fc7cfb3f7e1442f6d9c6a846d6d16 Author: Andre Heinecke Date: Fri Jul 20 10:27:26 2018 +0200 Also debug oom if debug oom_extra is set * src/common_indep.h (gpgol_release): Add line. (debug_oom): Also debug for oom_extra -- Debug oom is one of the debug settings that need to go in the future. diff --git a/src/common_indep.h b/src/common_indep.h index 9261d5f..0997594 100644 --- a/src/common_indep.h +++ b/src/common_indep.h @@ -258,7 +258,8 @@ char *trim_trailing_spaces (char *string); while(*_vptr) { *_vptr=0; _vptr++; } \ } while(0) -#define debug_oom (opt.enable_debug & DBG_OOM) +#define debug_oom ((opt.enable_debug & DBG_OOM) || \ + (opt.enable_debug & DBG_OOM_EXTRA)) #define debug_oom_extra (opt.enable_debug & DBG_OOM_EXTRA) void log_debug (const char *fmt, ...) __attribute__ ((format (printf,1,2))); void log_error (const char *fmt, ...) __attribute__ ((format (printf,1,2))); @@ -279,8 +280,8 @@ void log_hexdump (const void *buf, size_t buflen, const char *fmt, { \ if (X && opt.enable_debug & DBG_OOM_EXTRA) \ { \ - log_debug ("%s:%s: Object: %p released ref: %lu \n", \ - SRCNAME, __func__, X, X->Release()); \ + log_debug ("%s:%s:%i: Object: %p released ref: %lu \n", \ + SRCNAME, __func__, __LINE__, X, X->Release()); \ memdbg_released (X); \ } \ else if (X) \ commit 74c6f5d78ee6bf31fc70ef5ad0b6cd3b3656a0aa Author: Andre Heinecke Date: Fri Jul 20 10:26:48 2018 +0200 Decorate eventsink with memdbg helpers * src/eventsink.h: Add memdbg helpers diff --git a/src/eventsink.h b/src/eventsink.h index 5468c41..12b1b35 100644 --- a/src/eventsink.h +++ b/src/eventsink.h @@ -176,6 +176,7 @@ LPDISPATCH install_ ## subcls ## _sink (LPDISPATCH object) \ pCPC = (LPCONNECTIONPOINTCONTAINER)disp; \ pCP = NULL; \ hr = pCPC->FindConnectionPoint (iidcls, &pCP); \ + memdbg_addRef (pCP); \ if (hr != S_OK || !pCP) \ { \ log_error ("%s:%s:%s: ConnectionPoint not found: hr=%#lx", \ @@ -185,6 +186,7 @@ LPDISPATCH install_ ## subcls ## _sink (LPDISPATCH object) \ } \ sink = new subcls; /* Note: Advise does another AddRef. */ \ hr = pCP->Advise ((LPUNKNOWN)sink, &cookie); \ + memdbg_addRef (sink); \ gpgol_release (pCPC); \ if (hr != S_OK) \ { \ @@ -210,7 +212,7 @@ void detach_ ## subcls ## _sink (LPDISPATCH obj) \ \ if (debug_oom_extra) \ log_debug ("%s:%s:%s: Called", SRCNAME, #subcls, __func__); \ - hr = obj->QueryInterface (iidcls, (void**)&sink); \ + hr = gpgol_queryInterface (obj, iidcls, (void**)&sink); \ if (hr != S_OK || !sink) \ { \ log_error ("%s:%s:%s: invalid object passed: hr=%#lx", \ commit fe5ce6b8faf4503f8996f4bd10afdaa8b9aaba0c Author: Andre Heinecke Date: Fri Jul 20 08:28:58 2018 +0200 Fix minor ref leak * src/oomhelp.cpp (get_ol_ui_language): Release langsettings. diff --git a/src/oomhelp.cpp b/src/oomhelp.cpp index 7bf70eb..694ef59 100644 --- a/src/oomhelp.cpp +++ b/src/oomhelp.cpp @@ -2269,9 +2269,11 @@ get_ol_ui_language () dispparams.cArgs = 1; dispparams.cNamedArgs = 0; - if (invoke_oom_method_with_parms_type (langSettings, "LanguageID", &var, - &dispparams, - DISPATCH_PROPERTYGET)) + int ret = invoke_oom_method_with_parms_type (langSettings, "LanguageID", &var, + &dispparams, + DISPATCH_PROPERTYGET); + gpgol_release (langSettings); + if (ret) { TRACEPOINT; return 0; commit 05c70803c61420cc61f566b577117522ead3f1a4 Author: Andre Heinecke Date: Fri Jul 20 08:20:18 2018 +0200 Start memdbg interface for COM ref counting * src/Makefile.am: Add memdbg files. * src/common_indep.h (gpgol_release): Call memdbg_released. * src/eventsink.h (install..sink): Use gpgol_queryInterface * src/mailitem-events.cpp (Unload): Dump memdbg maps after unload. * src/oomhelp.h (gpgol_queryInterface): New. * src/mimedataprovider.cpp (MimeDataProvider::MimeDataProvider): Register ref add. * src/oomhelp.cpp (gpgol_queryInterface): New. (get_object_name): Use non memdbg aware functions. (get_oom_object): Use gpgol_queryInterface. (get_oom_object): Print out refs when obtaining if. (get_oom_control_bytag, get_object_by_id), (get_oom_mapi_session): Use mdbg functions. -- The idea is that in the end we will trace all com reference obtains and releases to find mismatchs and additionally all malloc / frees and C++ dtor / ctor to find memory leaks and hopefully random instability or crashes caused by invalid ref counting. As we can't use valgrind or decent debugging in Outlook on Windows tracking it ourself seems to be useful. diff --git a/src/Makefile.am b/src/Makefile.am index d3d8b19..599394f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -51,6 +51,7 @@ gpgol_SOURCES = \ mailitem-events.cpp \ main.c \ mapihelp.cpp mapihelp.h \ + memdbg.cpp memdbg.h \ mimedataprovider.cpp mimedataprovider.h \ mimemaker.cpp mimemaker.h \ mlang-charset.cpp mlang-charset.h \ diff --git a/src/common_indep.h b/src/common_indep.h index 00921e6..9261d5f 100644 --- a/src/common_indep.h +++ b/src/common_indep.h @@ -30,6 +30,8 @@ #include "xmalloc.h" +#include "memdbg.h" + #ifdef HAVE_W32_SYSTEM /* Not so independenent ;-) need this for logging HANDLE */ # include @@ -279,6 +281,7 @@ void log_hexdump (const void *buf, size_t buflen, const char *fmt, { \ log_debug ("%s:%s: Object: %p released ref: %lu \n", \ SRCNAME, __func__, X, X->Release()); \ + memdbg_released (X); \ } \ else if (X) \ { \ diff --git a/src/eventsink.h b/src/eventsink.h index 4d81dfe..5468c41 100644 --- a/src/eventsink.h +++ b/src/eventsink.h @@ -165,8 +165,8 @@ LPDISPATCH install_ ## subcls ## _sink (LPDISPATCH object) \ DWORD cookie; \ \ disp = NULL; \ - hr = object->QueryInterface (IID_IConnectionPointContainer, \ - (LPVOID*)&disp); \ + hr = gpgol_queryInterface (object, IID_IConnectionPointContainer, \ + (LPVOID*)&disp); \ if (hr != S_OK || !disp) \ { \ log_error ("%s:%s:%s: IConnectionPoint not supported: hr=%#lx", \ @@ -199,6 +199,7 @@ LPDISPATCH install_ ## subcls ## _sink (LPDISPATCH object) \ sink->m_cookie = cookie; \ sink->m_pCP = pCP; \ object->AddRef (); \ + memdbg_addRef (object); \ sink->m_object = object; \ return (LPDISPATCH)sink; \ } \ diff --git a/src/mailitem-events.cpp b/src/mailitem-events.cpp index ab100c5..0769df1 100644 --- a/src/mailitem-events.cpp +++ b/src/mailitem-events.cpp @@ -727,6 +727,7 @@ EVENT_SINK_INVOKE(MailItemEvents) delete m_mail; log_oom_extra ("%s:%s: deletion done", SRCNAME, __func__); + memdbg_dump (); return S_OK; } /* Fallthrough */ diff --git a/src/memdbg.cpp b/src/memdbg.cpp new file mode 100644 index 0000000..cd506dc --- /dev/null +++ b/src/memdbg.cpp @@ -0,0 +1,174 @@ +/* @file memdbg.cpp + * @brief Memory debugging helpers + * + * Copyright (C) 2018 Intevation GmbH + * + * This file is part of GpgOL. + * + * GpgOL 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. + * + * GpgOL 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 Lesser 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 . + */ + +#include "config.h" + +#include "memdbg.h" + +#include "common_indep.h" + +#include + +#include +#include + +std::map cppObjs; +std::map olObjs; +std::map olNames; + +GPGRT_LOCK_DEFINE (memdbg_log); + +#define DBGGUARD if (!(opt.enable_debug & DBG_OOM_EXTRA)) return + +#ifdef HAVE_W32_SYSTEM +# include "oomhelp.h" +#endif + +static void +register_name (void *obj) +{ +#ifdef HAVE_W32_SYSTEM + auto it = olNames.find (obj); + + if (it != olNames.end()) + { + return; + } + + char *name = get_object_name ((LPUNKNOWN)obj); + if (!name) + { + return; + } + std::string sName = name; + olNames.insert (std::make_pair (obj, sName)); + xfree (name); +#else + (void) obj; +#endif +} + +void +memdbg_addRef (void *obj) +{ + DBGGUARD; + + if (!obj) + { + return; + } + + gpgrt_lock_lock (&memdbg_log); + + auto it = olObjs.find (obj); + + if (it == olObjs.end()) + { + it = olObjs.insert (std::make_pair (obj, 0)).first; + register_name (obj); + } + it->second++; + + gpgrt_lock_unlock (&memdbg_log); +} + +void +memdbg_released (void *obj) +{ + DBGGUARD; + + if (!obj) + { + return; + } + + gpgrt_lock_lock (&memdbg_log); + + auto it = olObjs.find (obj); + + if (it == olObjs.end()) + { + log_error ("%s:%s Released %p without query if!!", + SRCNAME, __func__, obj); + gpgrt_lock_unlock (&memdbg_log); + return; + } + + it->second--; + + if (it->second < 0) + { + log_error ("%s:%s Released %p below zero", + SRCNAME, __func__, obj); + } + gpgrt_lock_unlock (&memdbg_log); +} + +void +memdbg_ctor (const char *objName) +{ + (void)objName; +} + +void +memdbg_dtor (const char *objName) +{ + (void)objName; + +} + +void +memdbg_dump () +{ + gpgrt_lock_lock (&memdbg_log); + log_debug("" +"------------------------------MEMORY DUMP----------------------------------"); + + log_debug("-- C++ Objects --"); + for (const auto &pair: cppObjs) + { + log_debug("%s\t: %i", pair.first.c_str(), pair.second); + } + log_debug("-- C++ End --"); + log_debug("-- OL Objects --"); + for (const auto &pair: olObjs) + { + if (!pair.second) + { + continue; + } + const auto it = olNames.find (pair.first); + if (it == olNames.end()) + { + log_debug("%p\t: %i", pair.first, pair.second); + } + else + { + log_debug("%p:%s\t: %i", pair.first, + it->second.c_str (), pair.second); + } + } + log_debug("-- OL End --"); + + log_debug("" +"------------------------------MEMORY END ----------------------------------"); + gpgrt_lock_unlock (&memdbg_log); +} diff --git a/src/memdbg.h b/src/memdbg.h new file mode 100644 index 0000000..a9ea4c5 --- /dev/null +++ b/src/memdbg.h @@ -0,0 +1,44 @@ +#ifndef MEMDBG_H +#define MEMDBG_H + +/* @file memdbg.h + * @brief Memory debugging helpers + * + * Copyright (C) 2018 Intevation GmbH + * + * This file is part of GpgOL. + * + * GpgOL 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. + * + * GpgOL 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 Lesser 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 . + */ + +#ifdef __cplusplus +extern "C" { +#if 0 +} +#endif +#endif + +void memdbg_addRef (void *obj); +void memdbg_released (void *obj); + +void memdbg_ctor (const char *objName); +void memdbg_dtor (const char *objName); + +void memdbg_dump(void); + +#ifdef __cplusplus +} +#endif + +#endif //MEMDBG_H diff --git a/src/mimedataprovider.cpp b/src/mimedataprovider.cpp index 92be963..2899f43 100644 --- a/src/mimedataprovider.cpp +++ b/src/mimedataprovider.cpp @@ -501,6 +501,7 @@ MimeDataProvider::MimeDataProvider(LPSTREAM stream, bool no_headers): if (stream) { stream->AddRef (); + memdbg_addRef (stream); } else { diff --git a/src/oomhelp.cpp b/src/oomhelp.cpp index a5822b5..7bf70eb 100644 --- a/src/oomhelp.cpp +++ b/src/oomhelp.cpp @@ -33,6 +33,16 @@ #include "oomhelp.h" #include "gpgoladdin.h" +HRESULT +gpgol_queryInterface (LPUNKNOWN pObj, REFIID riid, LPVOID FAR *ppvObj) +{ + HRESULT ret = pObj->QueryInterface (riid, ppvObj); + if ((opt.enable_debug & DBG_OOM_EXTRA) && *ppvObj) + { + memdbg_addRef (*ppvObj); + } + return ret; +} /* Return a malloced string with the utf-8 encoded name of the object or NULL if not available. */ @@ -48,6 +58,7 @@ get_object_name (LPUNKNOWN obj) if (!obj) goto leave; + /* We can't use gpgol_queryInterface here to avoid recursion */ obj->QueryInterface (IID_IDispatch, (void **)&disp); if (!disp) goto leave; @@ -73,9 +84,9 @@ get_object_name (LPUNKNOWN obj) leave: if (tinfo) - gpgol_release (tinfo); + tinfo->Release (); if (disp) - gpgol_release (disp); + disp->Release (); return name; } @@ -188,7 +199,7 @@ get_oom_object (LPDISPATCH pStart, const char *fullname) gpgol_release (pDisp); pDisp = NULL; } - if (pObj->QueryInterface (IID_IDispatch, (LPVOID*)&pDisp) != S_OK) + if (gpgol_queryInterface (pObj, IID_IDispatch, (LPVOID*)&pDisp) != S_OK) { log_error ("%s:%s Object does not support IDispatch", SRCNAME, __func__); @@ -203,7 +214,13 @@ get_oom_object (LPDISPATCH pStart, const char *fullname) return NULL; /* The object has no IDispatch interface. */ if (!*fullname) { - log_oom ("%s:%s: got %p",SRCNAME, __func__, pDisp); + if ((opt.enable_debug & DBG_OOM)) + { + pDisp->AddRef (); + int ref = pDisp->Release (); + log_oom ("%s:%s: got %p with %i refs", + SRCNAME, __func__, pDisp, ref); + } return pDisp; /* Ready. */ } @@ -327,6 +344,7 @@ get_oom_object (LPDISPATCH pStart, const char *fullname) } pObj = vtResult.pdispVal; + memdbg_addRef (pObj); } log_debug ("%s:%s: no object", SRCNAME, __func__); return NULL; @@ -753,7 +771,8 @@ get_oom_control_bytag (LPDISPATCH pDisp, const char *tag) SysFreeString (bstring); if (hr == S_OK && rVariant.vt == VT_DISPATCH && rVariant.pdispVal) { - rVariant.pdispVal->QueryInterface (IID_IDispatch, (LPVOID*)&result); + gpgol_queryInterface (rVariant.pdispVal, IID_IDispatch, + (LPVOID*)&result); gpgol_release (rVariant.pdispVal); if (!result) log_debug ("%s:%s: Object with tag `%s' has no dispatch intf.", @@ -1459,7 +1478,7 @@ get_object_by_id (LPDISPATCH pDisp, REFIID id) if (!pDisp) return NULL; - if (pDisp->QueryInterface (id, (void **)&disp) != S_OK) + if (gpgol_queryInterface(pDisp, id, (void **)&disp) != S_OK) return NULL; return disp; } @@ -1636,7 +1655,7 @@ get_oom_mapi_session () return NULL; } session = NULL; - hr = mapiobj->QueryInterface (IID_IMAPISession, (void**)&session); + hr = gpgol_queryInterface (mapiobj, IID_IMAPISession, (void**)&session); gpgol_release (mapiobj); if (hr != S_OK || !session) { diff --git a/src/oomhelp.h b/src/oomhelp.h index 4430b0c..1991bee 100644 --- a/src/oomhelp.h +++ b/src/oomhelp.h @@ -369,4 +369,7 @@ int get_ex_major_version_for_addr (const char *mbox); int get_ol_ui_language (void); char *get_sender_SendUsingAccount (LPDISPATCH mailitem, bool *r_is_GSuite); + +/* memtracing query interface */ +HRESULT gpgol_queryInterface (LPUNKNOWN pObj, REFIID riid, LPVOID FAR *ppvObj); #endif /*OOMHELP_H*/ ----------------------------------------------------------------------- Summary of changes: src/Makefile.am | 1 + src/common_indep.h | 10 ++- src/eventsink.h | 9 +- src/gpgol.def | 1 - src/gpgoladdin.cpp | 18 +++- src/gpgoladdin.h | 2 +- src/mail.cpp | 13 +-- src/mailitem-events.cpp | 1 + src/mapihelp.cpp | 27 +++--- src/memdbg.cpp | 203 ++++++++++++++++++++++++++++++++++++++++++++ src/{xmalloc.h => memdbg.h} | 34 ++++---- src/mimedataprovider.cpp | 1 + src/mimemaker.cpp | 2 +- src/mlang-charset.cpp | 1 + src/olflange.cpp | 1 + src/oomhelp.cpp | 63 +++++++++++--- src/oomhelp.h | 7 ++ src/ribbon-callbacks.cpp | 3 +- 18 files changed, 341 insertions(+), 56 deletions(-) create mode 100644 src/memdbg.cpp copy src/{xmalloc.h => memdbg.h} (69%) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Fri Jul 20 10:59:26 2018 From: cvs at cvs.gnupg.org (by Maximilian Krambach) Date: Fri, 20 Jul 2018 10:59:26 +0200 Subject: [git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-77-ga965e3e Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, javascript-binding has been updated via a965e3e0b89521ad4f3898a8483161624c2e5848 (commit) from 50da3ff2fddf0d35541f798313e881fef3cff869 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit a965e3e0b89521ad4f3898a8483161624c2e5848 Author: Maximilian Krambach Date: Fri Jul 20 10:59:57 2018 +0200 js: repair BrowserTextExtension test -- * the signed message to verify was signed by a wrong test key diff --git a/lang/js/BrowserTestExtension/tests/verifyTest.js b/lang/js/BrowserTestExtension/tests/verifyTest.js index bf0f0c0..e8e2c76 100644 --- a/lang/js/BrowserTestExtension/tests/verifyTest.js +++ b/lang/js/BrowserTestExtension/tests/verifyTest.js @@ -30,14 +30,14 @@ let verifyData = { 'Matschige M?nsteraner Marshmallows\n' + '-----BEGIN PGP SIGNATURE-----\n' + '\n' + - 'iQEzBAEBCAAdFiEE34YHmHCyv9oBiN3shwTx6WpaVdQFAlsqWxYACgkQhwTx6Wpa\n' + - 'VdRaTQf9Fj8agQzbE6DtonewZVGzj1KmjjpyAypnDldY21lrN8zIaQ+aKqRVkVrV\n' + - '5A/MeUfoHh0b/9G1Co4LOuNjGS14GRNlFvPtxeA2mCwlk7kgP2i6ekbHdEXWcG9c\n' + - 'gSbzdJ3EgfVCFNkC/yhldXSLOJZ7oyiGEteDpi8dDSa9dIprT++sQ4kRuR8jPrIi\n' + - 'UUY+DltG3it7PybcTFfQm53I0mtnpFsizzCmgyJAkfG5fwVL3uWwbYGofD049PSu\n' + - '6IEkSY74r8JbAbkCOiF/ln40RYGSwM0Ta5rrb3A3MixZNL/a1r17oljkaWz8e8VT\n' + - 'N7NUgBHwbIQ4e3RLuUU8fF3ICCGDOw==\n' + - '=oGai\n' + + 'iQEzBAEBCAAdFiEE1Bc1uRI2/biCBIxaIwFjXu/wywUFAltRoiMACgkQIwFjXu/w\n' + + 'ywUvagf6ApQbZbTPOROqfTfxAPdtzJsSDKHla6D0G5wom2gJbAVb0B2YS1c3Gjpq\n' + + 'I4kTKT1W1RRkne0mK9cexf4sjb5DQcV8PLhfmmAJEpljDFei6i/E309BvW4CZ4rG\n' + + 'jiurf8CkaNkrwn2fXJDaT4taVCX3V5FQAlgLxgOrm1zjiGA4mz98gi5zL4hvZXF9\n' + + 'dHY0jLwtQMVUO99q+5XC1TJfPsnteWL9m4e/YYPfYJMZZso+/0ib/yX5vHCk7RXH\n' + + 'CfhY40nMXSYdfl8mDOhvnKcCvy8qxetFv9uCX06OqepAamu/bvxslrzocRyJ/eq0\n' + + 'T2JfzEN+E7Y3PB8UwLgp/ZRmG8zRrQ==\n' + + '=ioB6\n' + '-----END PGP SIGNATURE-----\n' }; ----------------------------------------------------------------------- Summary of changes: lang/js/BrowserTestExtension/tests/verifyTest.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Fri Jul 20 12:05:40 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Fri, 20 Jul 2018 12:05:40 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-85-g2116eb9 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via 2116eb9008fd93506686219cbdb332b8c29f303e (commit) via 37a852d0b5190357fd311904fb817a7b2745d6da (commit) via 4db938bdf940d401fe0f2361ad14398d09a02b8d (commit) via 3fcd5d9daa2224da5a7b2eda992e60c54ce7e2ec (commit) via 5cc4867b399a48b281e7375f122da11bbf32e2a2 (commit) via 961c03f8c4226f57c5b25744a7330e551eb14dff (commit) from 35e663754f7d407adf4ae6864f41da288f11ecb9 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 2116eb9008fd93506686219cbdb332b8c29f303e Author: Andre Heinecke Date: Fri Jul 20 12:04:50 2018 +0200 Fix minor ref leaks * src/oomhelp.cpp (get_account_for_mail): Release account. (ensure_category_exists): Release categories on error. diff --git a/src/oomhelp.cpp b/src/oomhelp.cpp index 8ca1d75..462d44e 100644 --- a/src/oomhelp.cpp +++ b/src/oomhelp.cpp @@ -1817,6 +1817,7 @@ ensure_category_exists (LPDISPATCH application, const char *category, int color) if (!category_obj) { TRACEPOINT; + gpgol_release (categories); break; } char *name = get_oom_string (category_obj, "Name"); @@ -2085,6 +2086,7 @@ get_account_for_mail (const char *mbox) if (!smtpAddr) { + gpgol_release (account); TRACEPOINT; continue; } @@ -2094,6 +2096,7 @@ get_account_for_mail (const char *mbox) xfree (smtpAddr); return account; } + gpgol_release (account); xfree (smtpAddr); } gpgol_release (accounts); commit 37a852d0b5190357fd311904fb817a7b2745d6da Author: Andre Heinecke Date: Fri Jul 20 12:04:10 2018 +0200 Fix ref leak in get_oom_recipients * src/oomhelp.cpp (get_oom_recipients): Release addrEntry. diff --git a/src/oomhelp.cpp b/src/oomhelp.cpp index 2da1703..8ca1d75 100644 --- a/src/oomhelp.cpp +++ b/src/oomhelp.cpp @@ -1374,6 +1374,7 @@ get_oom_recipients (LPDISPATCH recipients, bool *r_err) gpgol_release (addrEntry); continue; } + gpgol_release (addrEntry); char *resolved = get_pa_string (recipient, PR_SMTP_ADDRESS_DASL); if (resolved) commit 4db938bdf940d401fe0f2361ad14398d09a02b8d Author: Andre Heinecke Date: Fri Jul 20 12:03:03 2018 +0200 Add missing memdbg_addRefs * src/mapihelp.cpp (mapi_get_attach): Add missing addRef. * src/mimemaker.cpp (create_mapi_attachment): Ditto. diff --git a/src/mapihelp.cpp b/src/mapihelp.cpp index 6956e43..f1beb9d 100644 --- a/src/mapihelp.cpp +++ b/src/mapihelp.cpp @@ -2553,6 +2553,7 @@ mapi_get_attach (LPMESSAGE message, return NULL; hr = message->OpenAttach (item->mapipos, NULL, MAPI_BEST_ACCESS, &att); + memdbg_addRef (att); if (FAILED (hr)) { log_error ("%s:%s: can't open attachment at %d: hr=%#lx", diff --git a/src/mimemaker.cpp b/src/mimemaker.cpp index 29dcb3c..4dd55a9 100644 --- a/src/mimemaker.cpp +++ b/src/mimemaker.cpp @@ -143,6 +143,7 @@ create_mapi_attachment (LPMESSAGE message, sink_t sink, sink->cb_data = NULL; sink->writefnc = NULL; hr = message->CreateAttach(NULL, 0, &pos, &att); + memdbg_addRef (att); if (hr) { log_error ("%s:%s: can't create attachment: hr=%#lx\n", commit 3fcd5d9daa2224da5a7b2eda992e60c54ce7e2ec Author: Andre Heinecke Date: Fri Jul 20 12:02:10 2018 +0200 Add ptr and line to addRef dbg output * src/memdbg.h (memdbg_addRef): Debug out the line. -- This makes it easy to find where leaked objects were referenced. diff --git a/src/memdbg.cpp b/src/memdbg.cpp index 088767f..341e105 100644 --- a/src/memdbg.cpp +++ b/src/memdbg.cpp @@ -92,7 +92,7 @@ register_name (void *obj) } void -memdbg_addRef (void *obj) +_memdbg_addRef (void *obj) { DBGGUARD; diff --git a/src/memdbg.h b/src/memdbg.h index a9ea4c5..37437bd 100644 --- a/src/memdbg.h +++ b/src/memdbg.h @@ -29,7 +29,17 @@ extern "C" { #endif #endif -void memdbg_addRef (void *obj); +#define memdbg_addRef(X) \ +{ \ + if (X) \ + { \ + log_oom_extra ("%s:%s:%i AddRef on %p", \ + SRCNAME, __func__, __LINE__, X); \ + _memdbg_addRef (X); \ + } \ +} + +void _memdbg_addRef (void *obj); void memdbg_released (void *obj); void memdbg_ctor (const char *objName); commit 5cc4867b399a48b281e7375f122da11bbf32e2a2 Author: Andre Heinecke Date: Fri Jul 20 12:01:23 2018 +0200 Fix attach table leak * src/cryptcontroller.cpp (CryptController::collect_data): Fix table leak. diff --git a/src/cryptcontroller.cpp b/src/cryptcontroller.cpp index 993c953..265bc60 100644 --- a/src/cryptcontroller.cpp +++ b/src/cryptcontroller.cpp @@ -116,6 +116,7 @@ CryptController::collect_data () utf8_gettext ("Can't encrypt / sign an empty message."), utf8_gettext ("GpgOL"), MB_OK); gpgol_release (message); + mapi_release_attach_table (att_table); xfree (body); return -1; } @@ -156,12 +157,15 @@ CryptController::collect_data () log_error ("%s:%s: Collecting body and attachments failed.", SRCNAME, __func__); gpgol_release (message); + mapi_release_attach_table (att_table); return -1; } /* Message is no longer needed */ gpgol_release (message); + mapi_release_attach_table (att_table); + /* Set the input buffer to start. */ m_input.seek (0, SEEK_SET); return 0; commit 961c03f8c4226f57c5b25744a7330e551eb14dff Author: Andre Heinecke Date: Fri Jul 20 11:18:34 2018 +0200 Fix ref leak in setDoAutosecure_m * src/mail.cpp (Mail::setDoAutosecure_m): Release msg. diff --git a/src/mail.cpp b/src/mail.cpp index 38ee1d0..bdb6d7f 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -3369,10 +3369,12 @@ Mail::setDoAutosecure_m (bool value) SRCNAME, __func__, m_mailitem); m_first_autosecure_check = false; m_manual_crypto_opts = true; + gpgol_release (msg); return; } m_first_autosecure_check = false; set_gpgol_draft_info_flags (msg, value ? 3 : 0); + gpgol_release (msg); gpgoladdin_invalidate_ui(); } ----------------------------------------------------------------------- Summary of changes: src/cryptcontroller.cpp | 4 ++++ src/mail.cpp | 2 ++ src/mapihelp.cpp | 1 + src/memdbg.cpp | 2 +- src/memdbg.h | 12 +++++++++++- src/mimemaker.cpp | 1 + src/oomhelp.cpp | 4 ++++ 7 files changed, 24 insertions(+), 2 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Fri Jul 20 15:01:38 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Fri, 20 Jul 2018 15:01:38 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-93-gaaafbc7 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via aaafbc793741fc64abe02af90f22e095e3133319 (commit) via a73aa07de8a1a36a8cc7f412635c1c10737be6fa (commit) via 02d0a5ba491ce6f075f3d3d195bc0894d8d7b45d (commit) via e53cbd17a7ea130f4cfac47858a5c1445c0fefb6 (commit) via 52e5891158e99fa532b02d1a13ff17566a7d583a (commit) via 6bbd203bc201f90b0394af24c105fa187f33ae6f (commit) via ad00070325e7f42380f9adeb27ac2a1a498c3e6a (commit) via aea2712f472a25c1a85906bcb0400ef3779771dd (commit) from 2116eb9008fd93506686219cbdb332b8c29f303e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit aaafbc793741fc64abe02af90f22e095e3133319 Author: Andre Heinecke Date: Fri Jul 20 15:00:05 2018 +0200 Add tracing for update body * src/mail.cpp (Mail::updateBody_o): Trace calls. -- This seems to hang sometimes so lets make sure that it is actually the oom call that hangs. diff --git a/src/mail.cpp b/src/mail.cpp index a72bc3d..b7c6e02 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -1174,8 +1174,10 @@ Mail::updateBody_o () char *converted = ansi_charset_to_utf8 (charset.c_str(), html.c_str(), html.size(), codepage); + TRACEPOINT; int ret = put_oom_string (m_mailitem, "HTMLBody", converted ? converted : ""); + TRACEPOINT; xfree (converted); if (ret) { @@ -1293,7 +1295,9 @@ Mail::updateBody_o () char *converted = ansi_charset_to_utf8 (plain_charset.c_str(), body.c_str(), body.size(), codepage); + TRACEPOINT; int ret = put_oom_string (m_mailitem, "Body", converted ? converted : ""); + TRACEPOINT; xfree (converted); if (ret) { commit a73aa07de8a1a36a8cc7f412635c1c10737be6fa Author: Andre Heinecke Date: Fri Jul 20 14:58:15 2018 +0200 Print error if addin is accessed after shutdown * src/gpgoladdin.cpp (GpgolAddin::get_instace): Print error when accessed. -- I thought this might be happening. diff --git a/src/gpgoladdin.cpp b/src/gpgoladdin.cpp index cf75cc1..5adfb20 100644 --- a/src/gpgoladdin.cpp +++ b/src/gpgoladdin.cpp @@ -1117,6 +1117,11 @@ GpgolAddin::get_instance () { addin_instance = new GpgolAddin (); } + if (addin_instance->isShutdown ()) + { + log_error ("%s:%s: Get instance after shutdown", + SRCNAME, __func__); + } return addin_instance; } diff --git a/src/gpgoladdin.h b/src/gpgoladdin.h index e2ae977..a8c121b 100644 --- a/src/gpgoladdin.h +++ b/src/gpgoladdin.h @@ -212,6 +212,7 @@ public: crypto mails. */ void shutdown (); LPDISPATCH get_application () { return m_application; } + bool isShutdown() { return m_shutdown; }; private: ULONG m_lRef; commit 02d0a5ba491ce6f075f3d3d195bc0894d8d7b45d Author: Andre Heinecke Date: Fri Jul 20 14:57:34 2018 +0200 Implement cpp ctor / dtor counting * src/memdbg.cpp (memdbg_ctor, memdbg_dtor): Implement. diff --git a/src/memdbg.cpp b/src/memdbg.cpp index 4f26fa6..3f68ae1 100644 --- a/src/memdbg.cpp +++ b/src/memdbg.cpp @@ -158,19 +158,66 @@ memdbg_released (void *obj) void memdbg_ctor (const char *objName) { - (void)objName; + DBGGUARD; + + if (!objName) + { + TRACEPOINT; + return; + } + + gpgrt_lock_lock (&memdbg_log); + + const std::string nameStr (objName); + + auto it = cppObjs.find (nameStr); + + if (it == cppObjs.end()) + { + it = cppObjs.insert (std::make_pair (nameStr, 0)).first; + } + it->second++; + + gpgrt_lock_unlock (&memdbg_log); } void memdbg_dtor (const char *objName) { - (void)objName; + DBGGUARD; + + if (!objName) + { + TRACEPOINT; + return; + } + + const std::string nameStr (objName); + auto it = cppObjs.find (nameStr); + + if (it == cppObjs.end()) + { + log_error ("%s:%s Dtor of %s before ctor", + SRCNAME, __func__, nameStr.c_str()); + gpgrt_lock_unlock (&memdbg_log); + return; + } + + it->second--; + + if (it->second < 0) + { + log_error ("%s:%s Dtor of %s more often then ctor", + SRCNAME, __func__, nameStr.c_str()); + } + gpgrt_lock_unlock (&memdbg_log); } void memdbg_dump () { + DBGGUARD; gpgrt_lock_lock (&memdbg_log); log_debug("" "------------------------------MEMORY DUMP----------------------------------"); commit e53cbd17a7ea130f4cfac47858a5c1445c0fefb6 Author: Andre Heinecke Date: Fri Jul 20 14:55:27 2018 +0200 Use reffing function as name for IUnknown * src/memdbg.cpp (_memdbg_addRef, register_name): Use calling function as the name for IUnknwon refs. -- This is very useful to see at a glance which refs are open. E.g. to see the event sink references. diff --git a/src/memdbg.cpp b/src/memdbg.cpp index 341e105..4f26fa6 100644 --- a/src/memdbg.cpp +++ b/src/memdbg.cpp @@ -44,12 +44,16 @@ GPGRT_LOCK_DEFINE (memdbg_log); /* Returns true on a name change */ static bool -register_name (void *obj) +register_name (void *obj, const char *nameSuggestion) { #ifdef HAVE_W32_SYSTEM char *name = get_object_name ((LPUNKNOWN)obj); + if (!name && nameSuggestion) + { + name = strdup (nameSuggestion); + } if (!name) { auto it = olNames.find (obj); @@ -92,7 +96,7 @@ register_name (void *obj) } void -_memdbg_addRef (void *obj) +_memdbg_addRef (void *obj, const char *nameSuggestion) { DBGGUARD; @@ -109,7 +113,7 @@ _memdbg_addRef (void *obj) { it = olObjs.insert (std::make_pair (obj, 0)).first; } - if (register_name (obj) && it->second) + if (register_name (obj, nameSuggestion) && it->second) { log_error ("%s:%s Name change without null ref on %p!", SRCNAME, __func__, obj); diff --git a/src/memdbg.h b/src/memdbg.h index 37437bd..49e34c1 100644 --- a/src/memdbg.h +++ b/src/memdbg.h @@ -35,11 +35,11 @@ extern "C" { { \ log_oom_extra ("%s:%s:%i AddRef on %p", \ SRCNAME, __func__, __LINE__, X); \ - _memdbg_addRef (X); \ + _memdbg_addRef (X, __func__); \ } \ } -void _memdbg_addRef (void *obj); +void _memdbg_addRef (void *obj, const char *nameSuggestion); void memdbg_released (void *obj); void memdbg_ctor (const char *objName); commit 52e5891158e99fa532b02d1a13ff17566a7d583a Author: Andre Heinecke Date: Fri Jul 20 14:53:53 2018 +0200 Add simple dtor / ctor counting of Cpp objs -- This adds memdbg trace function to the important objects to double check that we don't loose / leak any. diff --git a/src/attachment.cpp b/src/attachment.cpp index 68f8025..e626d26 100644 --- a/src/attachment.cpp +++ b/src/attachment.cpp @@ -27,10 +27,12 @@ Attachment::Attachment() { + memdbg_ctor ("Attachment"); } Attachment::~Attachment() { + memdbg_dtor ("Attachment"); log_debug ("%s:%s", SRCNAME, __func__); } diff --git a/src/cryptcontroller.cpp b/src/cryptcontroller.cpp index 265bc60..d97e891 100644 --- a/src/cryptcontroller.cpp +++ b/src/cryptcontroller.cpp @@ -68,6 +68,7 @@ CryptController::CryptController (Mail *mail, bool encrypt, bool sign, m_crypto_success (false), m_proto (proto) { + memdbg_ctor ("CryptController"); log_debug ("%s:%s: CryptController ctor for %p encrypt %i sign %i inline %i.", SRCNAME, __func__, mail, encrypt, sign, mail->getDoPGPInline ()); m_recipient_addrs = vector_to_cArray (mail->getCachedRecipients ()); @@ -75,6 +76,7 @@ CryptController::CryptController (Mail *mail, bool encrypt, bool sign, CryptController::~CryptController() { + memdbg_dtor ("CryptController"); log_debug ("%s:%s:%p", SRCNAME, __func__, m_mail); release_cArray (m_recipient_addrs); diff --git a/src/mail.cpp b/src/mail.cpp index bdb6d7f..a72bc3d 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -126,6 +126,7 @@ Mail::Mail (LPDISPATCH mailitem) : s_mail_map.insert (std::pair (mailitem, this)); gpgrt_lock_unlock (&mail_map_lock); s_last_mail = this; + memdbg_ctor ("Mail"); } GPGRT_LOCK_DEFINE(dtor_lock); @@ -152,6 +153,7 @@ Mail::~Mail() that the parser is alive even if the mail is deleted while parsing. */ gpgrt_lock_lock (&dtor_lock); + memdbg_dtor ("Mail"); log_oom_extra ("%s:%s: dtor: Mail: %p item: %p", SRCNAME, __func__, this, m_mailitem); std::map::iterator it; diff --git a/src/mimedataprovider.cpp b/src/mimedataprovider.cpp index 2899f43..e073b4b 100644 --- a/src/mimedataprovider.cpp +++ b/src/mimedataprovider.cpp @@ -489,6 +489,7 @@ MimeDataProvider::MimeDataProvider(bool no_headers) : m_has_html_body(false), m_collect_everything(no_headers) { + memdbg_ctor ("MimeDataProvider"); m_mime_ctx = (mime_context_t) xcalloc (1, sizeof *m_mime_ctx); m_mime_ctx->msg = rfc822parse_open (message_cb, this); m_mime_ctx->mimestruct_tail = &m_mime_ctx->mimestruct; @@ -525,6 +526,7 @@ MimeDataProvider::MimeDataProvider(FILE *stream, bool no_headers): MimeDataProvider::~MimeDataProvider() { + memdbg_dtor ("MimeDataProvider"); log_debug ("%s:%s", SRCNAME, __func__); while (m_mime_ctx->mimestruct) { diff --git a/src/parsecontroller.cpp b/src/parsecontroller.cpp index 323b1d3..1b19aba 100644 --- a/src/parsecontroller.cpp +++ b/src/parsecontroller.cpp @@ -80,6 +80,7 @@ ParseController::ParseController(LPSTREAM instream, msgtype_t type): m_type (type), m_block_html (false) { + memdbg_ctor ("ParseController"); log_mime_parser ("%s:%s: Creating parser for stream: %p of type %i" " expect no headers: %i expect no mime: %i", SRCNAME, __func__, instream, type, @@ -94,6 +95,7 @@ ParseController::ParseController(FILE *instream, msgtype_t type): m_type (type), m_block_html (false) { + memdbg_ctor ("ParseController"); log_mime_parser ("%s:%s: Creating parser for stream: %p of type %i", SRCNAME, __func__, instream, type); } @@ -101,6 +103,7 @@ ParseController::ParseController(FILE *instream, msgtype_t type): ParseController::~ParseController() { log_debug ("%s:%s", SRCNAME, __func__); + memdbg_dtor ("ParseController"); delete m_inputprovider; delete m_outputprovider; } commit 6bbd203bc201f90b0394af24c105fa187f33ae6f Author: Andre Heinecke Date: Fri Jul 20 14:51:30 2018 +0200 Accept multipart/mixed application/pgp-encrypted * src/mapihelp.cpp (change_message_class_ipm_note): Accept multipart/mixed with protocol application/pgp-encrypted. -- This happens when an encrypted mail is moved by Outlooks local filter move rules. GnuPG-Bug-Id: T4070 diff --git a/src/mapihelp.cpp b/src/mapihelp.cpp index 04f1be4..afe6d7f 100644 --- a/src/mapihelp.cpp +++ b/src/mapihelp.cpp @@ -1048,6 +1048,14 @@ change_message_class_ipm_note (LPMESSAGE message) class IPM.Note. */ newvalue = xstrdup ("IPM.Note.GpgOL.MultipartSigned"); } + else if (!strcmp (ct, "multipart/mixed") + && !strcmp (proto, "application/pgp-encrypted")) + { + /* This case happens if an encrypted mail is moved + by outlook local filter rules. + */ + newvalue = xstrdup ("IPM.Note.GpgOL.MultipartEncrypted"); + } xfree (proto); } else if (ct && !strcmp (ct, "application/ms-tnef")) commit ad00070325e7f42380f9adeb27ac2a1a498c3e6a Author: Andre Heinecke Date: Fri Jul 20 14:01:43 2018 +0200 Remove dead code and add some addRefs * src/mapihel.cpp, src/mapihelp.h (has_gpgol_body_name) (mapi_get_gpgol_body_attachment, mapi_delete_gpgol_body_attachment), (mapi_attachment_to_body): Removed. diff --git a/src/mapihelp.cpp b/src/mapihelp.cpp index f1beb9d..04f1be4 100644 --- a/src/mapihelp.cpp +++ b/src/mapihelp.cpp @@ -837,7 +837,8 @@ is_really_cms_encrypted (LPMESSAGE message) goto leave; } hr = message->OpenAttach (mapirows->aRow[pos].lpProps[0].Value.l, - NULL, MAPI_BEST_ACCESS, &att); + NULL, MAPI_BEST_ACCESS, &att); + memdbg_addRef (att); if (FAILED (hr)) { log_error ("%s:%s: can't open attachment %d (%ld): hr=%#lx", @@ -963,6 +964,7 @@ get_first_attach_mime_tag (LPMESSAGE message) } hr = message->OpenAttach (mapirows->aRow[pos].lpProps[0].Value.l, NULL, MAPI_BEST_ACCESS, &att); + memdbg_addRef (att); if (FAILED (hr)) { log_error ("%s:%s: can't open attachment %d (%ld): hr=%#lx", @@ -2444,6 +2446,7 @@ mapi_get_attach_as_stream (LPMESSAGE message, mapi_attach_item_t *item, return NULL; hr = message->OpenAttach (item->mapipos, NULL, MAPI_BEST_ACCESS, &att); + memdbg_addRef (att); if (FAILED (hr)) { log_error ("%s:%s: can't open attachment at %d: hr=%#lx", @@ -2588,6 +2591,7 @@ mapi_mark_moss_attach (LPMESSAGE message, mapi_attach_item_t *item) return -1; hr = message->OpenAttach (item->mapipos, NULL, MAPI_BEST_ACCESS, &att); + memdbg_addRef (att); if (FAILED (hr)) { log_error ("%s:%s: can't open attachment at %d: hr=%#lx", @@ -3177,36 +3181,6 @@ mapi_has_last_decrypted (LPMESSAGE message) } -/* Helper for mapi_get_gpgol_body_attachment. */ -static int -has_gpgol_body_name (LPATTACH obj) -{ - HRESULT hr; - LPSPropValue propval; - int yes = 0; - - hr = HrGetOneProp ((LPMAPIPROP)obj, PR_ATTACH_FILENAME, &propval); - if (FAILED(hr)) - return 0; - - if ( PROP_TYPE (propval->ulPropTag) == PT_UNICODE) - { - if (!wcscmp (propval->Value.lpszW, L"gpgol000.txt")) - yes = 1; - else if (!wcscmp (propval->Value.lpszW, L"gpgol000.htm")) - yes = 2; - } - else if ( PROP_TYPE (propval->ulPropTag) == PT_STRING8) - { - if (!strcmp (propval->Value.lpszA, "gpgol000.txt")) - yes = 1; - else if (!strcmp (propval->Value.lpszA, "gpgol000.htm")) - yes = 2; - } - MAPIFreeBuffer (propval); - return yes; -} - /* Helper to check whether the file name of OBJ is "smime.p7m". Returns on true if so. */ static int @@ -3239,320 +3213,6 @@ has_smime_filename (LPATTACH obj) } -/* Return the content of the body attachment of MESSAGE. The body - attachment is a hidden attachment created by us for later display. - If R_NBYTES is not NULL the number of bytes in the returned buffer - is stored there. If R_ISHTML is not NULL a flag indicating whether - the HTML is html formatted is stored there. If R_PROTECTED is not - NULL a flag indicating whether the message was protected is stored - there. If no body attachment can be found or on any other error an - error codes is returned and NULL is stored at R_BODY. Caller must - free the returned string. If NULL is passed for R_BODY, the - function will only test whether a body attachment is available and - return an error code if not. R_IS_HTML and R_PROTECTED are not - defined in this case. */ -int -mapi_get_gpgol_body_attachment (LPMESSAGE message, - char **r_body, size_t *r_nbytes, - int *r_ishtml, int *r_protected) -{ - HRESULT hr; - SizedSPropTagArray (1L, propAttNum) = { 1L, {PR_ATTACH_NUM} }; - LPMAPITABLE mapitable; - LPSRowSet mapirows; - unsigned int pos, n_attach; - ULONG moss_tag; - char *body = NULL; - int bodytype; - int found = 0; - - if (r_body) - *r_body = NULL; - if (r_ishtml) - *r_ishtml = 0; - if (r_protected) - *r_protected = 0; - - if (get_gpgolattachtype_tag (message, &moss_tag) ) - return -1; - - hr = message->GetAttachmentTable (0, &mapitable); - if (FAILED (hr)) - { - log_debug ("%s:%s: GetAttachmentTable failed: hr=%#lx", - SRCNAME, __func__, hr); - return -1; - } - - hr = HrQueryAllRows (mapitable, (LPSPropTagArray)&propAttNum, - NULL, NULL, 0, &mapirows); - if (FAILED (hr)) - { - log_debug ("%s:%s: HrQueryAllRows failed: hr=%#lx", - SRCNAME, __func__, hr); - gpgol_release (mapitable); - return -1; - } - n_attach = mapirows->cRows > 0? mapirows->cRows : 0; - if (!n_attach) - { - FreeProws (mapirows); - gpgol_release (mapitable); - log_debug ("%s:%s: No attachments at all", SRCNAME, __func__); - return -1; - } - log_debug ("%s:%s: message has %u attachments\n", - SRCNAME, __func__, n_attach); - - for (pos=0; pos < n_attach; pos++) - { - LPATTACH att; - - if (mapirows->aRow[pos].cValues < 1) - { - log_error ("%s:%s: invalid row at pos %d", SRCNAME, __func__, pos); - continue; - } - if (mapirows->aRow[pos].lpProps[0].ulPropTag != PR_ATTACH_NUM) - { - log_error ("%s:%s: invalid prop at pos %d", SRCNAME, __func__, pos); - continue; - } - hr = message->OpenAttach (mapirows->aRow[pos].lpProps[0].Value.l, - NULL, MAPI_BEST_ACCESS, &att); - if (FAILED (hr)) - { - log_error ("%s:%s: can't open attachment %d (%ld): hr=%#lx", - SRCNAME, __func__, pos, - mapirows->aRow[pos].lpProps[0].Value.l, hr); - continue; - } - if ((bodytype=has_gpgol_body_name (att)) - && get_gpgolattachtype (att, moss_tag) == ATTACHTYPE_FROMMOSS) - { - found = 1; - if (!r_body) - ; /* Body content has not been requested. */ - else - { - char *charset; - - if (get_attach_method (att) == ATTACH_BY_VALUE) - body = attach_to_buffer (att, r_nbytes); - if (body && (charset = mapi_get_gpgol_charset ((LPMESSAGE)att))) - { - /* We only support transcoding from Latin-1 for now. */ - if (strcmp (charset, "iso-8859-1") - && !strcmp (charset, "latin-1")) - log_debug ("%s:%s: Using Latin-1 instead of %s", - SRCNAME, __func__, charset); - xfree (charset); - charset = latin1_to_utf8 (body); - xfree (body); - body = charset; - } - } - gpgol_release (att); - if (r_ishtml) - *r_ishtml = (bodytype == 2); - break; - } - gpgol_release (att); - } - FreeProws (mapirows); - gpgol_release (mapitable); - if (!found) - { - log_error ("%s:%s: no suitable body attachment found", SRCNAME,__func__); - if (r_body) - *r_body = native_to_utf8 - (_("[The content of this message is not visible" - " due to an processing error in GpgOL.]")); - return -1; - } - - if (r_body) - *r_body = body; - else - xfree (body); /* (Should not happen.) */ - return 0; -} - - -/* Delete a possible body atatchment. Returns true if an atatchment - has been deleted. */ -int -mapi_delete_gpgol_body_attachment (LPMESSAGE message) -{ - HRESULT hr; - SizedSPropTagArray (1L, propAttNum) = { 1L, {PR_ATTACH_NUM} }; - LPMAPITABLE mapitable; - LPSRowSet mapirows; - unsigned int pos, n_attach; - ULONG moss_tag; - int found = 0; - - if (get_gpgolattachtype_tag (message, &moss_tag) ) - return 0; - - hr = message->GetAttachmentTable (0, &mapitable); - if (FAILED (hr)) - { - log_debug ("%s:%s: GetAttachmentTable failed: hr=%#lx", - SRCNAME, __func__, hr); - return 0; - } - - hr = HrQueryAllRows (mapitable, (LPSPropTagArray)&propAttNum, - NULL, NULL, 0, &mapirows); - if (FAILED (hr)) - { - log_debug ("%s:%s: HrQueryAllRows failed: hr=%#lx", - SRCNAME, __func__, hr); - gpgol_release (mapitable); - return 0; - } - n_attach = mapirows->cRows > 0? mapirows->cRows : 0; - if (!n_attach) - { - FreeProws (mapirows); - gpgol_release (mapitable); - return 0; /* No Attachments. */ - } - - for (pos=0; pos < n_attach; pos++) - { - LPATTACH att; - - if (mapirows->aRow[pos].cValues < 1) - { - log_error ("%s:%s: invalid row at pos %d", SRCNAME, __func__, pos); - continue; - } - if (mapirows->aRow[pos].lpProps[0].ulPropTag != PR_ATTACH_NUM) - { - log_error ("%s:%s: invalid prop at pos %d", SRCNAME, __func__, pos); - continue; - } - hr = message->OpenAttach (mapirows->aRow[pos].lpProps[0].Value.l, - NULL, MAPI_BEST_ACCESS, &att); - if (FAILED (hr)) - { - log_error ("%s:%s: can't open attachment %d (%ld): hr=%#lx", - SRCNAME, __func__, pos, - mapirows->aRow[pos].lpProps[0].Value.l, hr); - continue; - } - if (has_gpgol_body_name (att) - && get_gpgolattachtype (att, moss_tag) == ATTACHTYPE_FROMMOSS) - { - gpgol_release (att); - hr = message->DeleteAttach (mapirows->aRow[pos].lpProps[0].Value.l, - 0, NULL, 0); - if (hr) - log_error ("%s:%s: DeleteAttach failed: hr=%#lx\n", - SRCNAME, __func__, hr); - else - { - log_debug ("%s:%s: body attachment deleted\n", - SRCNAME, __func__); - found = 1; - - } - break; - } - gpgol_release (att); - } - FreeProws (mapirows); - gpgol_release (mapitable); - return found; -} - - -/* Copy the attachment ITEM of the message MESSAGE verbatim to the - PR_BODY property. Returns 0 on success. This function does not - call SaveChanges. */ -int -mapi_attachment_to_body (LPMESSAGE message, mapi_attach_item_t *item) -{ - int result = -1; - HRESULT hr; - LPATTACH att = NULL; - LPSTREAM instream = NULL; - LPSTREAM outstream = NULL; - LPUNKNOWN punk; - - if (!message || !item || item->end_of_table || item->mapipos == -1) - return -1; /* Error. */ - - hr = message->OpenAttach (item->mapipos, NULL, MAPI_BEST_ACCESS, &att); - if (FAILED (hr)) - { - log_error ("%s:%s: can't open attachment at %d: hr=%#lx", - SRCNAME, __func__, item->mapipos, hr); - goto leave; - } - if (item->method != ATTACH_BY_VALUE) - { - log_error ("%s:%s: attachment: method not supported", SRCNAME, __func__); - goto leave; - } - - hr = gpgol_openProperty (att, PR_ATTACH_DATA_BIN, &IID_IStream, - 0, 0, (LPUNKNOWN*) &instream); - if (FAILED (hr)) - { - log_error ("%s:%s: can't open data stream of attachment: hr=%#lx", - SRCNAME, __func__, hr); - goto leave; - } - - - punk = (LPUNKNOWN)outstream; - hr = gpgol_openProperty (message, PR_BODY_A, &IID_IStream, 0, - MAPI_CREATE|MAPI_MODIFY, &punk); - if (FAILED (hr)) - { - log_error ("%s:%s: can't open body stream for update: hr=%#lx", - SRCNAME, __func__, hr); - goto leave; - } - outstream = (LPSTREAM)punk; - - { - ULARGE_INTEGER cb; - cb.QuadPart = 0xffffffffffffffffll; - hr = instream->CopyTo (outstream, cb, NULL, NULL); - } - if (hr) - { - log_error ("%s:%s: can't copy streams: hr=%#lx\n", - SRCNAME, __func__, hr); - goto leave; - } - hr = outstream->Commit (0); - if (hr) - { - log_error ("%s:%s: commiting output stream failed: hr=%#lx", - SRCNAME, __func__, hr); - goto leave; - } - result = 0; - - leave: - if (outstream) - { - if (result) - outstream->Revert (); - gpgol_release (outstream); - } - if (instream) - gpgol_release (instream); - if (att) - gpgol_release (att); - return result; -} - /* Copy the MAPI body to a PGPBODY type attachment. */ int mapi_body_to_attachment (LPMESSAGE message) diff --git a/src/mapihelp.h b/src/mapihelp.h index ede2cbf..4fc34d2 100644 --- a/src/mapihelp.h +++ b/src/mapihelp.h @@ -106,13 +106,6 @@ char *mapi_get_message_content_type (LPMESSAGE message, char **r_protocol, char **r_smtype); int mapi_has_last_decrypted (LPMESSAGE message); -int mapi_get_gpgol_body_attachment (LPMESSAGE message, - char **r_body, size_t *r_nbytes, - int *r_ishtml, int *r_protected); - -int mapi_delete_gpgol_body_attachment (LPMESSAGE message); - -int mapi_attachment_to_body (LPMESSAGE message, mapi_attach_item_t *item); attachtype_t get_gpgolattachtype (LPATTACH obj, ULONG tag); commit aea2712f472a25c1a85906bcb0400ef3779771dd Author: Andre Heinecke Date: Fri Jul 20 13:15:49 2018 +0200 Fix ref leak on no object error * src/oomhelp.cpp (get_oom_object): Release pDisp always. -- This fixes a common reference leak from the check_inline_response codepath. Where it would leak for everything that is not an inline response. diff --git a/src/oomhelp.cpp b/src/oomhelp.cpp index 462d44e..1a11560 100644 --- a/src/oomhelp.cpp +++ b/src/oomhelp.cpp @@ -362,6 +362,7 @@ get_oom_object (LPDISPATCH pStart, const char *fullname) pObj = vtResult.pdispVal; memdbg_addRef (pObj); } + gpgol_release (pDisp); log_debug ("%s:%s: no object", SRCNAME, __func__); return NULL; } ----------------------------------------------------------------------- Summary of changes: src/attachment.cpp | 2 + src/cryptcontroller.cpp | 2 + src/gpgoladdin.cpp | 5 + src/gpgoladdin.h | 1 + src/mail.cpp | 6 + src/mapihelp.cpp | 358 ++--------------------------------------------- src/mapihelp.h | 7 - src/memdbg.cpp | 61 +++++++- src/memdbg.h | 4 +- src/mimedataprovider.cpp | 2 + src/oomhelp.cpp | 1 + src/parsecontroller.cpp | 3 + 12 files changed, 93 insertions(+), 359 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Fri Jul 20 15:39:23 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Fri, 20 Jul 2018 15:39:23 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-95-ga9c34f5 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via a9c34f58409c799ef22289d3bcf64b87866997c6 (commit) via 57dd3ee1dd73fb7f3152cee4841370090338caff (commit) from aaafbc793741fc64abe02af90f22e095e3133319 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit a9c34f58409c799ef22289d3bcf64b87866997c6 Author: Andre Heinecke Date: Fri Jul 20 15:24:11 2018 +0200 Don't print error in memdbg if caller changes * src/memdbg.cpp (register_name): Don't print error if the name changed and the calling function was used as the name. diff --git a/src/memdbg.cpp b/src/memdbg.cpp index 3f68ae1..0a50513 100644 --- a/src/memdbg.cpp +++ b/src/memdbg.cpp @@ -49,10 +49,12 @@ register_name (void *obj, const char *nameSuggestion) #ifdef HAVE_W32_SYSTEM char *name = get_object_name ((LPUNKNOWN)obj); + bool suggestionUsed = false; if (!name && nameSuggestion) { name = strdup (nameSuggestion); + suggestionUsed = true; } if (!name) { @@ -82,7 +84,7 @@ register_name (void *obj, const char *nameSuggestion) SRCNAME, __func__, obj, it->second.c_str(), sName.c_str()); it->second = sName; - return true; + return !suggestionUsed; } } else commit 57dd3ee1dd73fb7f3152cee4841370090338caff Author: Andre Heinecke Date: Fri Jul 20 15:21:34 2018 +0200 Make UI invalidation more deterministic * src/explorer-events.cpp (hasSelection, startWatchdog, changeSeen): New. * src/mail.cpp (do_parsing): Block invalidation while parsing. * src/windowmessages.cpp (blockInv, unblockInv): New. (delayed_invalidate_ui): Handle block inv state. * src/windowmessages.h: Update accordingly. -- UI Invalidation is extremly expensive and often a cause for crashes. So we should avoid it as much as possible. This code aims just to do that while still not skipping any required invalidation. diff --git a/src/explorer-events.cpp b/src/explorer-events.cpp index b9706db..d4087d1 100644 --- a/src/explorer-events.cpp +++ b/src/explorer-events.cpp @@ -62,6 +62,136 @@ typedef enum ViewSwitch = 0xF004 } ExplorerEvent; +/* + We need to avoid UI invalidations as much as possible as invalidations + can trigger reloads of mails and at a bad time can crash us. + + So we only invalidate the UI after we have handled the read event of + a mail and again after decrypt / verify. + + The problem is that we also need to update the UI when mails are + unselected so we don't show "Secure" if nothing is selected. + + On a switch from one Mail to another we see two selection changes. + One for the unselect the other for the select immediately after + each other. + + When we just have an unselect we see only one selection change. + + So after we detect the unselect we switch the state in our + explorerMap to unselect seen and start a WatchDog thread. + + That thread sleeps for 500ms and then checks if the state + was switched to select seen in the meantime. If + not it triggers the UI Invalidation in the GUI thread. + */ +#include + +typedef enum + { + WatchDogActive = 0x01, + UnselectSeen = 0x02, + SelectSeen = 0x04, + } SelectionState; + +std::map s_explorerMap; + +gpgrt_lock_t explorer_map_lock = GPGRT_LOCK_INITIALIZER; + +static bool +hasSelection (LPDISPATCH explorer) +{ + LPDISPATCH selection = get_oom_object (explorer, "Selection"); + + if (!selection) + { + TRACEPOINT; + return false; + } + + int count = get_oom_int (selection, "Count"); + gpgol_release (selection); + + if (count) + { + return true; + } + return false; +} + +static DWORD WINAPI +start_watchdog (LPVOID arg) +{ + LPDISPATCH explorer = (LPDISPATCH) arg; + + Sleep (500); + gpgrt_lock_lock (&explorer_map_lock); + + auto it = s_explorerMap.find (explorer); + + if (it == s_explorerMap.end ()) + { + log_error ("%s:%s: Watchdog for unknwon explorer %p", + SRCNAME, __func__, explorer); + gpgrt_lock_unlock (&explorer_map_lock); + return 0; + } + + if ((it->second & SelectSeen)) + { + log_oom_extra ("%s:%s: Cancel watchdog as we have seen a select %p", + SRCNAME, __func__, explorer); + it->second = SelectSeen; + } + else if ((it->second & UnselectSeen)) + { + log_debug ("%s:%s: Deteced unselect invalidating UI.", + SRCNAME, __func__); + it->second = UnselectSeen; + } + gpgrt_lock_unlock (&explorer_map_lock); + + do_in_ui_thread (INVALIDATE_UI, nullptr); + return 0; +} + +static void +changeSeen (LPDISPATCH explorer) +{ + gpgrt_lock_lock (&explorer_map_lock); + + auto it = s_explorerMap.find (explorer); + + if (it == s_explorerMap.end ()) + { + it = s_explorerMap.insert (std::make_pair (explorer, 0)).first; + } + + auto state = it->second; + bool has_selection = hasSelection (explorer); + + if (has_selection) + { + it->second = (state & WatchDogActive) + SelectSeen; + log_oom_extra ("%s:%s: Seen select for %p", + SRCNAME, __func__, explorer); + } + else + { + if ((it->second & WatchDogActive)) + { + log_oom_extra ("%s:%s: Seen unselect for %p but watchdog exists.", + SRCNAME, __func__, explorer); + } + else + { + CloseHandle (CreateThread (NULL, 0, start_watchdog, (LPVOID) explorer, + 0, NULL)); + } + it->second = UnselectSeen + WatchDogActive; + } + gpgrt_lock_unlock (&explorer_map_lock); +} EVENT_SINK_INVOKE(ExplorerEvents) { @@ -72,19 +202,7 @@ EVENT_SINK_INVOKE(ExplorerEvents) { log_oom_extra ("%s:%s: Selection change in explorer: %p", SRCNAME, __func__, this); - - HANDLE thread = CreateThread (NULL, 0, delayed_invalidate_ui, (LPVOID) this, 0, - NULL); - - if (!thread) - { - log_error ("%s:%s: Failed to create invalidate_ui thread.", - SRCNAME, __func__); - } - else - { - CloseHandle (thread); - } + changeSeen (m_object); break; } case Close: @@ -93,6 +211,9 @@ EVENT_SINK_INVOKE(ExplorerEvents) SRCNAME, __func__, this); GpgolAddin::get_instance ()->unregisterExplorerSink (this); + gpgrt_lock_lock (&explorer_map_lock); + s_explorerMap.erase (m_object); + gpgrt_lock_unlock (&explorer_map_lock); delete this; return S_OK; } diff --git a/src/mail.cpp b/src/mail.cpp index b7c6e02..ba134d2 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -733,6 +733,8 @@ do_parsing (LPVOID arg) gpgrt_lock_unlock (&dtor_lock); return 0; } + + blockInv (); /* This takes a shared ptr of parser. So the parser is still valid when the mail is deleted. */ auto parser = mail->parser (); @@ -755,6 +757,7 @@ do_parsing (LPVOID arg) SRCNAME, __func__, arg); gpgrt_lock_unlock (&invalidate_lock); gpgrt_lock_unlock (&parser_lock); + unblockInv(); return 0; } @@ -764,12 +767,14 @@ do_parsing (LPVOID arg) SRCNAME, __func__, arg); gpgrt_lock_unlock (&invalidate_lock); gpgrt_lock_unlock (&parser_lock); + unblockInv(); return -1; } parser->parse(); do_in_ui_thread (PARSING_DONE, arg); gpgrt_lock_unlock (&invalidate_lock); gpgrt_lock_unlock (&parser_lock); + unblockInv(); return 0; } diff --git a/src/windowmessages.cpp b/src/windowmessages.cpp index 3861127..9b5c46b 100644 --- a/src/windowmessages.cpp +++ b/src/windowmessages.cpp @@ -107,7 +107,7 @@ gpgol_window_proc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } case (INVALIDATE_LAST_MAIL): { - log_debug ("%s:%s: Invalidating last mail", + log_debug ("%s:%s: clearing last mail", SRCNAME, __func__); Mail::clearLastMail (); break; @@ -425,6 +425,8 @@ gpgrt_lock_t invalidate_lock = GPGRT_LOCK_INITIALIZER; static bool invalidation_in_progress; +static int invalidation_blocked = 0; + DWORD WINAPI delayed_invalidate_ui (LPVOID) { @@ -434,13 +436,26 @@ delayed_invalidate_ui (LPVOID) SRCNAME, __func__); return 0; } - gpgrt_lock_lock(&invalidate_lock); + TRACEPOINT; invalidation_in_progress = true; - /* We sleep here a bit to prevent invalidation immediately - after the selection change before we have started processing - the mail. */ - Sleep (250); + gpgrt_lock_lock(&invalidate_lock); + + int i = 0; + while (invalidation_blocked) + { + Sleep (100); + i++; + + if (i % 10 == 0) + { + log_debug ("%s:%s: Waiting for invalidation.", + SRCNAME, __func__); + } + + /* Do we need an abort statement here? */ + } do_in_ui_thread (INVALIDATE_UI, nullptr); + TRACEPOINT; invalidation_in_progress = false; gpgrt_lock_unlock(&invalidate_lock); return 0; @@ -452,3 +467,26 @@ close_mail (LPVOID mail) do_in_ui_thread (CLOSE, mail); return 0; } + +void +blockInv() +{ + invalidation_blocked++; + log_oom_extra ("%s:%s: Invalidation block count %i", + SRCNAME, __func__, invalidation_blocked); +} + +void +unblockInv() +{ + invalidation_blocked--; + log_oom_extra ("%s:%s: Invalidation block count %i", + SRCNAME, __func__, invalidation_blocked); + + if (invalidation_blocked < 0) + { + log_error ("%s:%s: Invalidation block mismatch", + SRCNAME, __func__); + invalidation_blocked = 0; + } +} diff --git a/src/windowmessages.h b/src/windowmessages.h index 2d6da49..29364a0 100644 --- a/src/windowmessages.h +++ b/src/windowmessages.h @@ -92,6 +92,15 @@ do_in_ui_thread_async (gpgol_wmsg_type type, void *data, int delay = 0); HHOOK create_message_hook(); +/** Block ui invalidation. The idea here is to further reduce + UI invalidations because depending on timing they might crash. + So we try to block invalidation for as long as it is a bad time + for us. */ +void blockInv (); + +/** Unblock ui invalidation */ +void unblockInv (); + DWORD WINAPI delayed_invalidate_ui (LPVOID); ----------------------------------------------------------------------- Summary of changes: src/explorer-events.cpp | 147 +++++++++++++++++++++++++++++++++++++++++++----- src/mail.cpp | 5 ++ src/memdbg.cpp | 4 +- src/windowmessages.cpp | 50 ++++++++++++++-- src/windowmessages.h | 9 +++ 5 files changed, 195 insertions(+), 20 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Sun Jul 22 17:36:45 2018 From: cvs at cvs.gnupg.org (by Ben McGinnes) Date: Sun, 22 Jul 2018 17:36:45 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-107-g4d1642b Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via 4d1642b11ea64b8009a8720d9b59e89636d691d2 (commit) via d7c5366d58d035d7b7119f955824e842d0b6bbe0 (commit) via b47e1bb98a8ff93cae560449bfa9103c47f4d4f8 (commit) from 5ef492c5635ae1677eed6f439a75a86a99dbbe18 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 4d1642b11ea64b8009a8720d9b59e89636d691d2 Author: Ben McGinnes Date: Mon Jul 23 01:16:31 2018 +1000 docs: python bindings howto * Fixed and tested the changes necessary for org-mode to correctly parse pythonic (Python 3) indentation. * Updated the source blocks to recommended upper case for BEGIN_SRC and END_SRC. * Tested and confirmed XHTML output matches correct examples. * Tested against pseudo-control output via exporting from org-mode to org-mode and then exporting that to XHTML. Remaining differences appear to be discarding the custom tags used to provide X[HT]ML id elements to each section which does not appear to offer any benefit. * Exporting directly to XHTML or other HTML output should no longer cause problems, but if there are any then the first step should be exporting from org-to-org and then exporting that to XHTML. Tested-by: Ben McGinnes Signed-off-by: Ben McGinnes diff --git a/lang/python/docs/GPGMEpythonHOWTOen.org b/lang/python/docs/GPGMEpythonHOWTOen.org index c40772f..a712ec2 100644 --- a/lang/python/docs/GPGMEpythonHOWTOen.org +++ b/lang/python/docs/GPGMEpythonHOWTOen.org @@ -340,41 +340,41 @@ pattern is upper or lower case. So this is the best method: -#+begin_src python -i +#+BEGIN_SRC python -i import gpg k = gpg.Context().keylist(pattern="258E88DCBD3CD44D8E7AB43F6ECB6AF0DEADBEEF") keys = list(k) -#+end_src +#+END_SRC This is passable and very likely to be common: -#+begin_src python -i +#+BEGIN_SRC python -i import gpg k = gpg.Context().keylist(pattern="0x6ECB6AF0DEADBEEF") keys = list(k) -#+end_src +#+END_SRC And this is a really bad idea: -#+begin_src python -i +#+BEGIN_SRC python -i import gpg k = gpg.Context().keylist(pattern="0xDEADBEEF") keys = list(k) -#+end_src +#+END_SRC Alternatively it may be that the intention is to create a list of keys which all match a particular search string. For instance all the addresses at a particular domain, like this: -#+begin_src python -i +#+BEGIN_SRC python -i import gpg ncsc = gpg.Context().keylist(pattern="ncsc.mil") nsa = list(ncsc) -#+end_src +#+END_SRC *** Counting keys @@ -386,7 +386,7 @@ Counting the number of keys in your public keybox (=pubring.kbx=), the format which has superseded the old keyring format (=pubring.gpg= and =secring.gpg=), or the number of secret keys is a very simple task. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg c = gpg.Context() @@ -403,7 +403,7 @@ print(""" Number of secret keys: {0} Number of public keys: {1} """.format(secnum, pubnum)) -#+end_src +#+END_SRC ** Get key @@ -424,22 +424,22 @@ secret keys as well. This first example demonstrates selecting the current key of Werner Koch, which is due to expire at the end of 2018: -#+begin_src python -i +#+BEGIN_SRC python -i import gpg fingerprint = "80615870F5BAD690333686D0F2AD85AC1E42B367" key = gpg.Context().get_key(fingerprint) -#+end_src +#+END_SRC Whereas this example demonstrates selecting the author's current key with the =secret= key word argument set to =True=: -#+begin_src python -i +#+BEGIN_SRC python -i import gpg fingerprint = "DB4724E6FA4286C92B4E55C4321E4E2373590E5D" key = gpg.Context().get_key(fingerprint, secret=True) -#+end_src +#+END_SRC It is, of course, quite possible to select expired, disabled and revoked keys with this function, but only to effectively display @@ -463,7 +463,7 @@ keyservers via the web using the requests module. Since requests returns the content as a bytes literal object, we can then use that directly to import the resulting data into our keybox. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg import os.path import requests @@ -498,13 +498,12 @@ elif result is not None and hasattr(result, "considered") is True: The key IDs for all considered keys were: """.format(num_keys, new_revs, new_sigs, new_subs, new_uids, new_scrt, - nochange)) + nochange)) for i in range(num_keys): - print(result.imports[i].fpr) - print("") + print("{0}\n".format(result.imports[i].fpr)) else: pass -#+end_src +#+END_SRC *NOTE:* When searching for a key ID of any length or a fingerprint (without spaces), the SKS servers require the the leading =0x= @@ -538,13 +537,13 @@ alternative, the =key_export_minimal()= method, will do the same thing except producing a minimised output with extra signatures and third party signatures or certifications removed. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg import os.path import sys print(""" - This script exports one or more public keys. +This script exports one or more public keys. """) c = gpg.Context(armor=True) @@ -568,9 +567,9 @@ else: if homedir.startswith("~"): if os.path.exists(os.path.expanduser(homedir)) is True: - c.home_dir = os.path.expanduser(homedir) + c.home_dir = os.path.expanduser(homedir) else: - pass + pass elif os.path.exists(homedir) is True: c.home_dir = homedir else: @@ -583,17 +582,17 @@ except: if result is not None: with open(keyfile, "wb") as f: - f.write(result) + f.write(result) else: pass -#+end_src +#+END_SRC It is important to note that the result will only return =None= when a pattern has been entered for =logrus=, but it has not matched any keys. When the search pattern itself is set to =None= this triggers the exporting of the entire public keybox. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg import os.path import sys @@ -623,9 +622,9 @@ else: if homedir.startswith("~"): if os.path.exists(os.path.expanduser(homedir)) is True: - c.home_dir = os.path.expanduser(homedir) + c.home_dir = os.path.expanduser(homedir) else: - pass + pass elif os.path.exists(homedir) is True: c.home_dir = homedir else: @@ -638,10 +637,10 @@ except: if result is not None: with open(keyfile, "wb") as f: - f.write(result) + f.write(result) else: pass -#+end_src +#+END_SRC *** Exporting secret keys @@ -657,7 +656,7 @@ The following example exports the secret key to a file which is then set with the same permissions as the output files created by the command line secret key export options. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg import os import os.path @@ -690,9 +689,9 @@ else: if homedir.startswith("~"): if os.path.exists(os.path.expanduser(homedir)) is True: - c.home_dir = os.path.expanduser(homedir) + c.home_dir = os.path.expanduser(homedir) else: - pass + pass elif os.path.exists(homedir) is True: c.home_dir = homedir else: @@ -705,11 +704,11 @@ except: if result is not None: with open(keyfile, "wb") as f: - f.write(result) + f.write(result) os.chmod(keyfile, 0o600) else: pass -#+end_src +#+END_SRC Alternatively the approach of the following script can be used. This longer example saves the exported secret key(s) in files in the GnuPG @@ -718,7 +717,7 @@ readable and writable by the user. It also exports the secret key(s) twice in order to output both GPG binary (=.gpg=) and ASCII armoured (=.asc=) files. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg import os import os.path @@ -760,9 +759,9 @@ else: if homedir.startswith("~"): if os.path.exists(os.path.expanduser(homedir)) is True: - c.home_dir = os.path.expanduser(homedir) + c.home_dir = os.path.expanduser(homedir) else: - pass + pass elif os.path.exists(homedir) is True: c.home_dir = homedir else: @@ -770,16 +769,16 @@ else: if c.home_dir is not None: if c.home_dir.endswith("/"): - gpgfile = "{0}{1}.gpg".format(c.home_dir, keyfile) - ascfile = "{0}{1}.asc".format(c.home_dir, keyfile) + gpgfile = "{0}{1}.gpg".format(c.home_dir, keyfile) + ascfile = "{0}{1}.asc".format(c.home_dir, keyfile) else: - gpgfile = "{0}/{1}.gpg".format(c.home_dir, keyfile) - ascfile = "{0}/{1}.asc".format(c.home_dir, keyfile) + gpgfile = "{0}/{1}.gpg".format(c.home_dir, keyfile) + ascfile = "{0}/{1}.asc".format(c.home_dir, keyfile) else: if os.path.exists(os.environ["GNUPGHOME"]) is True: - hd = os.environ["GNUPGHOME"] + hd = os.environ["GNUPGHOME"] else: - hd = subprocess.getoutput(gpgconfcmd) + hd = subprocess.getoutput(gpgconfcmd) gpgfile = "{0}/{1}.gpg".format(hd, keyfile) ascfile = "{0}/{1}.asc".format(hd, keyfile) @@ -792,18 +791,18 @@ except: if a_result is not None: with open(ascfile, "wb") as f: - f.write(a_result) + f.write(a_result) os.chmod(ascfile, 0o600) else: pass if b_result is not None: with open(gpgfile, "wb") as f: - f.write(b_result) + f.write(b_result) os.chmod(gpgfile, 0o600) else: pass -#+end_src +#+END_SRC * Basic Functions @@ -850,7 +849,7 @@ trust model settings for recipient keys (defaults to =False=); =expect_sign=, prepare for signing (defaults to =False=); =compress=, compresses the plaintext prior to encryption (defaults to =True=). -#+begin_src python -i +#+BEGIN_SRC python -i import gpg a_key = "0x12345678DEADBEEF" @@ -867,14 +866,14 @@ ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=False) with open("secret_plans.txt.asc", "wb") as afile: afile.write(ciphertext) -#+end_src +#+END_SRC Though this is even more likely to be used like this; with the plaintext input read from a file, the recipient keys used for encryption regardless of key trust status and the encrypted output also encrypted to any preconfigured keys set in the =gpg.conf= file: -#+begin_src python -i +#+BEGIN_SRC python -i import gpg a_key = "0x12345678DEADBEEF" @@ -885,12 +884,12 @@ with open("secret_plans.txt", "rb") as afile: c = gpg.Context(armor=True) rkey = list(c.keylist(pattern=a_key, secret=False)) ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=True, - always_trust=True, - add_encrypt_to=True) + always_trust=True, + add_encrypt_to=True) with open("secret_plans.txt.asc", "wb") as afile: afile.write(ciphertext) -#+end_src +#+END_SRC If the =recipients= paramater is empty then the plaintext is encrypted symmetrically. If no =passphrase= is supplied as a parameter or via a @@ -911,7 +910,7 @@ email address on the =gnupg.org= domain,[fn:3] but does /not/ encrypt to a default key or other key which is configured to normally encrypt to. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg text = b"""Oh look, another test message. @@ -933,24 +932,24 @@ logrus = [] for i in range(len(rpattern)): if rpattern[i].can_encrypt == 1: - logrus.append(rpattern[i]) + logrus.append(rpattern[i]) ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, - sign=False, always_trust=True) + sign=False, always_trust=True) with open("secret_plans.txt.asc", "wb") as afile: afile.write(ciphertext) -#+end_src +#+END_SRC All it would take to change the above example to sign the message and also encrypt the message to any configured default keys would be to change the =c.encrypt= line to this: -#+begin_src python -i +#+BEGIN_SRC python -i ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, - always_trust=True, - add_encrypt_to=True) -#+end_src + always_trust=True, + add_encrypt_to=True) +#+END_SRC The only keyword arguments requiring modification are those for which the default values are changing. The default value of =sign= is @@ -962,7 +961,7 @@ are not trusted (e.g. not signed or locally signed) then the encryption will raise an error. It is possible to mitigate this somewhat with something more like this: -#+begin_src python -i +#+BEGIN_SRC python -i import gpg with open("secret_plans.txt.asc", "rb") as afile: @@ -974,27 +973,27 @@ logrus = [] for i in range(len(rpattern)): if rpattern[i].can_encrypt == 1: - logrus.append(rpattern[i]) + logrus.append(rpattern[i]) try: - ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, - add_encrypt_to=True) + ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, + add_encrypt_to=True) except gpg.errors.InvalidRecipients as e: - for i in range(len(e.recipients)): - for n in range(len(logrus)): - if logrus[n].fpr == e.recipients[i].fpr: - logrus.remove(logrus[n]) - else: - pass - try: - ciphertext, result, sign_result = c.encrypt(text, - recipients=logrus, - add_encrypt_to=True) - with open("secret_plans.txt.asc", "wb") as afile: - afile.write(ciphertext) - except: - pass -#+end_src + for i in range(len(e.recipients)): + for n in range(len(logrus)): + if logrus[n].fpr == e.recipients[i].fpr: + logrus.remove(logrus[n]) + else: + pass + try: + ciphertext, result, sign_result = c.encrypt(text, + recipients=logrus, + add_encrypt_to=True) + with open("secret_plans.txt.asc", "wb") as afile: + afile.write(ciphertext) + except: + pass +#+END_SRC This will attempt to encrypt to all the keys searched for, then remove invalid recipients if it fails and try again. @@ -1014,7 +1013,7 @@ to modify the Context prior to conducting the decryption and since the Context is only used once, setting it to =c= simply adds lines for no gain. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg ciphertext = input("Enter path and filename of encrypted file: ") @@ -1022,17 +1021,17 @@ newfile = input("Enter path and filename of file to save decrypted data to: ") with open(ciphertext, "rb") as cfile: try: - plaintext, result, verify_result = gpg.Context().decrypt(cfile) + plaintext, result, verify_result = gpg.Context().decrypt(cfile) except gpg.errors.GPGMEError as e: - plaintext = None - print(e) + plaintext = None + print(e) - if plaintext is not None: - with open(newfile, "wb") as nfile: +if plaintext is not None: + with open(newfile, "wb") as nfile: nfile.write(plaintext) else: - pass -#+end_src + pass +#+END_SRC The data available in =plaintext= in this example is the decrypted content as a byte object, the recipient key IDs and algorithms in @@ -1059,13 +1058,13 @@ default key specified and there is more than one secret key available it may be necessary to specify the key or keys with which to sign messages and files. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg logrus = input("Enter the email address or string to match signing keys to: ") hancock = gpg.Context().keylist(pattern=logrus, secret=True) sig_src = list(hancock) -#+end_src +#+END_SRC The signing examples in the following sections include the explicitly designated =signers= parameter in two of the five examples; once where @@ -1100,7 +1099,7 @@ multiple keys are involved; from the preferences saved into the key itself or by comparison with the preferences with all other keys involved. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg text0 = """Declaration of ... something. @@ -1113,14 +1112,14 @@ signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.NORMAL) with open("/path/to/statement.txt.asc", "w") as afile: afile.write(signed_data.decode()) -#+end_src +#+END_SRC Though everything in this example is accurate, it is more likely that reading the input data from another file and writing the result to a new file will be performed more like the way it is done in the next example. Even if the output format is ASCII armoured. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg with open("/path/to/statement.txt", "rb") as tfile: @@ -1131,7 +1130,7 @@ signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.NORMAL) with open("/path/to/statement.txt.sig", "wb") as afile: afile.write(signed_data) -#+end_src +#+END_SRC *** Detached signing messages and files @@ -1143,7 +1142,7 @@ Detached signatures will often be needed in programmatic uses of GPGME, either for signing files (e.g. tarballs of code releases) or as a component of message signing (e.g. PGP/MIME encoded email). -#+begin_src python -i +#+BEGIN_SRC python -i import gpg text0 = """Declaration of ... something. @@ -1156,12 +1155,12 @@ signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.DETACH) with open("/path/to/statement.txt.asc", "w") as afile: afile.write(signed_data.decode()) -#+end_src +#+END_SRC As with normal signatures, detached signatures are best handled as byte literals, even when the output is ASCII armoured. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg with open("/path/to/statement.txt", "rb") as tfile: @@ -1172,7 +1171,7 @@ signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.DETACH) with open("/path/to/statement.txt.sig", "wb") as afile: afile.write(signed_data) -#+end_src +#+END_SRC *** Clearsigning messages or text @@ -1184,7 +1183,7 @@ Though PGP/in-line messages are no longer encouraged in favour of PGP/MIME, there is still sometimes value in utilising in-line signatures. This is where clear-signed messages or text is of value. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg text0 = """Declaration of ... something. @@ -1197,12 +1196,12 @@ signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR) with open("/path/to/statement.txt.asc", "w") as afile: afile.write(signed_data.decode()) -#+end_src +#+END_SRC In spite of the appearance of a clear-signed message, the data handled by GPGME in signing it must still be byte literals. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg with open("/path/to/statement.txt", "rb") as tfile: @@ -1213,7 +1212,7 @@ signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR) with open("/path/to/statement.txt.asc", "wb") as afile: afile.write(signed_data) -#+end_src +#+END_SRC ** Signature verification @@ -1229,7 +1228,7 @@ with files and data with detached signatures. The following example is intended for use with the default signing method where the file was not ASCII armoured: -#+begin_src python -i +#+BEGIN_SRC python -i import gpg import time @@ -1247,21 +1246,21 @@ except gpg.errors.BadSignatures as e: if verified is True: for i in range(len(result.signatures)): - sign = result.signatures[i] - print("""Good signature from: + sign = result.signatures[i] + print("""Good signature from: {0} with key {1} made at {2} """.format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, - time.ctime(sign.timestamp))) + time.ctime(sign.timestamp))) else: pass -#+end_src +#+END_SRC Whereas this next example, which is almost identical would work with normal ASCII armoured files and with clear-signed files: -#+begin_src python -i +#+BEGIN_SRC python -i import gpg import time @@ -1279,22 +1278,22 @@ except gpg.errors.BadSignatures as e: if verified is True: for i in range(len(result.signatures)): - sign = result.signatures[i] - print("""Good signature from: + sign = result.signatures[i] + print("""Good signature from: {0} with key {1} made at {2} """.format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, - time.ctime(sign.timestamp))) + time.ctime(sign.timestamp))) else: pass -#+end_src +#+END_SRC In both of the previous examples it is also possible to compare the original data that was signed against the signed data in =data= to see if it matches with something like this: -#+begin_src python -i +#+BEGIN_SRC python -i with open(filename, "rb") as afile: text = afile.read() @@ -1302,7 +1301,7 @@ if text == data: print("Good signature.") else: pass -#+end_src +#+END_SRC The following two examples, however, deal with detached signatures. With his method of verification the data that was signed does not get @@ -1310,7 +1309,7 @@ returned since it is already being explicitly referenced in the first argument of =c.verify=. So =data= is =None= and only the information in =result= is available. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg import time @@ -1328,18 +1327,18 @@ except gpg.errors.BadSignatures as e: if verified is True: for i in range(len(result.signatures)): - sign = result.signatures[i] - print("""Good signature from: + sign = result.signatures[i] + print("""Good signature from: {0} with key {1} made at {2} """.format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, - time.ctime(sign.timestamp))) + time.ctime(sign.timestamp))) else: pass -#+end_src +#+END_SRC -#+begin_src python -i +#+BEGIN_SRC python -i import gpg import time @@ -1357,16 +1356,16 @@ except gpg.errors.BadSignatures as e: if verified is True: for i in range(len(result.signatures)): - sign = result.signatures[i] - print("""Good signature from: + sign = result.signatures[i] + print("""Good signature from: {0} with key {1} made at {2} """.format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, - time.ctime(sign.timestamp))) + time.ctime(sign.timestamp))) else: pass -#+end_src +#+END_SRC * Creating keys and subkeys @@ -1387,7 +1386,7 @@ clearance, so his keys will be 3072-bit keys. The pre-configured =gpg.conf= file which sets cipher, digest and other preferences contains the following configuration parameters: -#+begin_src conf +#+BEGIN_SRC conf expert allow-freeform-uid allow-secret-key-import @@ -1400,7 +1399,7 @@ preferences contains the following configuration parameters: personal-cipher-preferences TWOFISH CAMELLIA256 AES256 CAMELLIA192 AES192 CAMELLIA128 AES BLOWFISH IDEA CAST5 3DES personal-digest-preferences SHA512 SHA384 SHA256 SHA224 RIPEMD160 SHA1 personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed -#+end_src +#+END_SRC ** Primary key @@ -1423,7 +1422,7 @@ be the passphrase and if =passphrase= is set to =True= then gpg-agent will launch pinentry to prompt for a passphrase. For the sake of convenience, these examples will keep =passphrase= set to =None=. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg c = gpg.Context() @@ -1432,8 +1431,8 @@ c.home_dir = "~/.gnupg-dm" userid = "Danger Mouse " dmkey = c.create_key(userid, algorithm="rsa3072", expires_in=31536000, - sign=True, certify=True) -#+end_src + sign=True, certify=True) +#+END_SRC One thing to note here is the use of setting the =c.home_dir= parameter. This enables generating the key or keys in a different @@ -1451,22 +1450,22 @@ already set and the correct directory and file permissions. The successful generation of the key can be confirmed via the returned =GenkeyResult= object, which includes the following data: -#+begin_src python -i +#+BEGIN_SRC python -i print(""" - Fingerprint: {0} - Primary Key: {1} - Public Key: {2} - Secret Key: {3} - Sub Key: {4} - User IDs: {5} - """.format(dmkey.fpr, dmkey.primary, dmkey.pubkey, dmkey.seckey, dmkey.sub, - dmkey.uid)) -#+end_src + Fingerprint: {0} + Primary Key: {1} + Public Key: {2} + Secret Key: {3} + Sub Key: {4} +User IDs: {5} +""".format(dmkey.fpr, dmkey.primary, dmkey.pubkey, dmkey.seckey, dmkey.sub, + dmkey.uid)) +#+END_SRC Alternatively the information can be confirmed using the command line program: -#+begin_src shell +#+BEGIN_SRC shell bash-4.4$ gpg --homedir ~/.gnupg-dm -K ~/.gnupg-dm/pubring.kbx ---------------------- @@ -1475,7 +1474,7 @@ program: uid [ultimate] Danger Mouse bash-4.4$ -#+end_src +#+END_SRC As with generating keys manually, to preconfigure expanded preferences for the cipher, digest and compression algorithms, the =gpg.conf= file @@ -1483,7 +1482,7 @@ must contain those details in the home directory in which the new key is being generated. I used a cut down version of my own =gpg.conf= file in order to be able to generate this: -#+begin_src shell +#+BEGIN_SRC shell bash-4.4$ gpg --homedir ~/.gnupg-dm --edit-key 177B7C25DB99745EE2EE13ED026D2F19E99E63AA showpref quit Secret key is available. @@ -1499,7 +1498,7 @@ file in order to be able to generate this: Features: MDC, Keyserver no-modify bash-4.4$ -#+end_src +#+END_SRC ** Subkeys @@ -1518,7 +1517,7 @@ primary key. Since Danger Mouse is a security conscious secret agent, this subkey will only be valid for about six months, half the length of the primary key. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg c = gpg.Context() @@ -1526,26 +1525,26 @@ c.home_dir = "~/.gnupg-dm" key = c.get_key(dmkey.fpr, secret=True) dmsub = c.create_subkey(key, algorithm="rsa3072", expires_in=15768000, - encrypt=True) -#+end_src + encrypt=True) +#+END_SRC As with the primary key, the results here can be checked with: -#+begin_src python -i +#+BEGIN_SRC python -i print(""" - Fingerprint: {0} - Primary Key: {1} - Public Key: {2} - Secret Key: {3} - Sub Key: {4} - User IDs: {5} - """.format(dmsub.fpr, dmsub.primary, dmsub.pubkey, dmsub.seckey, dmsub.sub, - dmsub.uid)) -#+end_src + Fingerprint: {0} + Primary Key: {1} + Public Key: {2} + Secret Key: {3} + Sub Key: {4} +User IDs: {5} +""".format(dmsub.fpr, dmsub.primary, dmsub.pubkey, dmsub.seckey, dmsub.sub, + dmsub.uid)) +#+END_SRC As well as on the command line with: -#+begin_src shell +#+BEGIN_SRC shell bash-4.4$ gpg --homedir ~/.gnupg-dm -K ~/.gnupg-dm/pubring.kbx ---------------------- @@ -1555,7 +1554,7 @@ As well as on the command line with: ssb rsa3072 2018-03-15 [E] [expires: 2018-09-13] bash-4.4$ -#+end_src +#+END_SRC ** User IDs @@ -1574,7 +1573,7 @@ ID to an existing key is much simpler. The method used to do this is =key_add_uid= and the only arguments it takes are for the =key= and the new =uid=. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg c = gpg.Context() @@ -1585,11 +1584,11 @@ key = c.get_key(dmfpr, secret=True) uid = "Danger Mouse " c.key_add_uid(key, uid) -#+end_src +#+END_SRC Unsurprisingly the result of this is: -#+begin_src shell +#+BEGIN_SRC shell bash-4.4$ gpg --homedir ~/.gnupg-dm -K ~/.gnupg-dm/pubring.kbx ---------------------- @@ -1600,7 +1599,7 @@ Unsurprisingly the result of this is: ssb rsa3072 2018-03-15 [E] [expires: 2018-09-13] bash-4.4$ -#+end_src +#+END_SRC *** Revokinging User IDs @@ -1611,7 +1610,7 @@ Unsurprisingly the result of this is: Revoking a user ID is a fairly similar process, except that it uses the =key_revoke_uid= method. -#+begin_src python -i +#+BEGIN_SRC python -i import gpg c = gpg.Context() @@ -1622,7 +1621,7 @@ key = c.get_key(dmfpr, secret=True) uid = "Danger Mouse " c.key_revoke_uid(key, uid) -#+end_src +#+END_SRC ** Key certification @@ -1651,7 +1650,7 @@ it is case sensitive. To sign Danger Mouse's key for just the initial user ID with a signature which will last a little over a month, do this: -#+begin_src python -i +#+BEGIN_SRC python -i import gpg c = gpg.Context() @@ -1660,7 +1659,7 @@ uid = "Danger Mouse " dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" key = c.get_key(dmfpr, secret=True) c.key_sign(key, uids=uid, expires_in=2764800) -#+end_src +#+END_SRC * Miscellaneous work-arounds @@ -1682,16 +1681,16 @@ MUAs readily. The following code, however, provides a work-around for obtaining this information in Python. -#+begin_src python -i +#+BEGIN_SRC python -i import subprocess lines = subprocess.getoutput("gpgconf --list-options gpg").splitlines() for i in range(len(lines)): if lines[i].startswith("group") is True: - line = lines[i] + line = lines[i] else: - pass + pass groups = line.split(":")[-1].replace('"', '').split(',') @@ -1704,7 +1703,7 @@ for i in range(len(groups)): for i in range(len(group_lists)): group_lists[i][1] = group_lists[i][1].split() -#+end_src +#+END_SRC The result of that code is that =group_lines= is a list of lists where =group_lines[i][0]= is the name of the group and =group_lines[i][1]= commit d7c5366d58d035d7b7119f955824e842d0b6bbe0 Author: Ben McGinnes Date: Mon Jul 23 00:21:05 2018 +1000 doc: python bindings howto * Another retrofitting of the HOWTO Python example code, this time following adjustments to python-mode configuration and having trawled through the org-mode mailing lists for clues. diff --git a/lang/python/docs/GPGMEpythonHOWTOen.org b/lang/python/docs/GPGMEpythonHOWTOen.org index df37226..c40772f 100644 --- a/lang/python/docs/GPGMEpythonHOWTOen.org +++ b/lang/python/docs/GPGMEpythonHOWTOen.org @@ -340,40 +340,40 @@ pattern is upper or lower case. So this is the best method: -#+begin_src python - import gpg +#+begin_src python -i +import gpg - k = gpg.Context().keylist(pattern="258E88DCBD3CD44D8E7AB43F6ECB6AF0DEADBEEF") - keys = list(k) +k = gpg.Context().keylist(pattern="258E88DCBD3CD44D8E7AB43F6ECB6AF0DEADBEEF") +keys = list(k) #+end_src This is passable and very likely to be common: -#+begin_src python - import gpg +#+begin_src python -i +import gpg - k = gpg.Context().keylist(pattern="0x6ECB6AF0DEADBEEF") - keys = list(k) +k = gpg.Context().keylist(pattern="0x6ECB6AF0DEADBEEF") +keys = list(k) #+end_src And this is a really bad idea: -#+begin_src python - import gpg +#+begin_src python -i +import gpg - k = gpg.Context().keylist(pattern="0xDEADBEEF") - keys = list(k) +k = gpg.Context().keylist(pattern="0xDEADBEEF") +keys = list(k) #+end_src Alternatively it may be that the intention is to create a list of keys which all match a particular search string. For instance all the addresses at a particular domain, like this: -#+begin_src python - import gpg +#+begin_src python -i +import gpg - ncsc = gpg.Context().keylist(pattern="ncsc.mil") - nsa = list(ncsc) +ncsc = gpg.Context().keylist(pattern="ncsc.mil") +nsa = list(ncsc) #+end_src @@ -386,23 +386,23 @@ Counting the number of keys in your public keybox (=pubring.kbx=), the format which has superseded the old keyring format (=pubring.gpg= and =secring.gpg=), or the number of secret keys is a very simple task. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - c = gpg.Context() - seckeys = c.keylist(pattern=None, secret=True) - pubkeys = c.keylist(pattern=None, secret=False) +c = gpg.Context() +seckeys = c.keylist(pattern=None, secret=True) +pubkeys = c.keylist(pattern=None, secret=False) - seclist = list(seckeys) - secnum = len(seclist) +seclist = list(seckeys) +secnum = len(seclist) - publist = list(pubkeys) - pubnum = len(publist) +publist = list(pubkeys) +pubnum = len(publist) - print(""" +print(""" Number of secret keys: {0} Number of public keys: {1} - """.format(secnum, pubnum)) +""".format(secnum, pubnum)) #+end_src @@ -424,21 +424,21 @@ secret keys as well. This first example demonstrates selecting the current key of Werner Koch, which is due to expire at the end of 2018: -#+begin_src python - import gpg +#+begin_src python -i +import gpg - fingerprint = "80615870F5BAD690333686D0F2AD85AC1E42B367" - key = gpg.Context().get_key(fingerprint) +fingerprint = "80615870F5BAD690333686D0F2AD85AC1E42B367" +key = gpg.Context().get_key(fingerprint) #+end_src Whereas this example demonstrates selecting the author's current key with the =secret= key word argument set to =True=: -#+begin_src python - import gpg +#+begin_src python -i +import gpg - fingerprint = "DB4724E6FA4286C92B4E55C4321E4E2373590E5D" - key = gpg.Context().get_key(fingerprint, secret=True) +fingerprint = "DB4724E6FA4286C92B4E55C4321E4E2373590E5D" +key = gpg.Context().get_key(fingerprint, secret=True) #+end_src It is, of course, quite possible to select expired, disabled and @@ -463,30 +463,30 @@ keyservers via the web using the requests module. Since requests returns the content as a bytes literal object, we can then use that directly to import the resulting data into our keybox. -#+begin_src python - import gpg - import os.path - import requests - - c = gpg.Context() - url = "https://sks-keyservers.net/pks/lookup" - pattern = input("Enter the pattern to search for key or user IDs: ") - payload = { "op": "get", "search": pattern } - - r = requests.get(url, verify=True, params=payload) - result = c.key_import(r.content) - - if result is not None and hasattr(result, "considered") is False: - print(result) - elif result is not None and hasattr(result, "considered") is True: - num_keys = len(result.imports) - new_revs = result.new_revocations - new_sigs = result.new_signatures - new_subs = result.new_sub_keys - new_uids = result.new_user_ids - new_scrt = result.secret_imported - nochange = result.unchanged - print(""" +#+begin_src python -i +import gpg +import os.path +import requests + +c = gpg.Context() +url = "https://sks-keyservers.net/pks/lookup" +pattern = input("Enter the pattern to search for key or user IDs: ") +payload = { "op": "get", "search": pattern } + +r = requests.get(url, verify=True, params=payload) +result = c.key_import(r.content) + +if result is not None and hasattr(result, "considered") is False: + print(result) +elif result is not None and hasattr(result, "considered") is True: + num_keys = len(result.imports) + new_revs = result.new_revocations + new_sigs = result.new_signatures + new_subs = result.new_sub_keys + new_uids = result.new_user_ids + new_scrt = result.secret_imported + nochange = result.unchanged + print(""" The total number of keys considered for import was: {0} Number of keys revoked: {1} @@ -497,13 +497,13 @@ directly to import the resulting data into our keybox. Number of unchanged keys: {6} The key IDs for all considered keys were: - """.format(num_keys, new_revs, new_sigs, new_subs, new_uids, new_scrt, - nochange)) - for i in range(num_keys): - print(result.imports[i].fpr) - print("") - else: - pass +""".format(num_keys, new_revs, new_sigs, new_subs, new_uids, new_scrt, + nochange)) + for i in range(num_keys): + print(result.imports[i].fpr) + print("") +else: + pass #+end_src *NOTE:* When searching for a key ID of any length or a fingerprint @@ -538,54 +538,54 @@ alternative, the =key_export_minimal()= method, will do the same thing except producing a minimised output with extra signatures and third party signatures or certifications removed. -#+begin_src python - import gpg - import os.path - import sys +#+begin_src python -i +import gpg +import os.path +import sys - print(""" +print(""" This script exports one or more public keys. - """) - - c = gpg.Context(armor=True) - - if len(sys.argv) >= 4: - keyfile = sys.argv[1] - logrus = sys.argv[2] - homedir = sys.argv[3] - elif len(sys.argv) == 3: - keyfile = sys.argv[1] - logrus = sys.argv[2] - homedir = input("Enter the GPG configuration directory path (optional): ") - elif len(sys.argv) == 2: - keyfile = sys.argv[1] - logrus = input("Enter the UID matching the key(s) to export: ") - homedir = input("Enter the GPG configuration directory path (optional): ") - else: - keyfile = input("Enter the path and filename to save the secret key to: ") - logrus = input("Enter the UID matching the key(s) to export: ") - homedir = input("Enter the GPG configuration directory path (optional): ") - - if homedir.startswith("~"): - if os.path.exists(os.path.expanduser(homedir)) is True: - c.home_dir = os.path.expanduser(homedir) - else: - pass - elif os.path.exists(homedir) is True: - c.home_dir = homedir - else: - pass - - try: - result = c.key_export(pattern=logrus) - except: - result = c.key_export(pattern=None) - - if result is not None: - with open(keyfile, "wb") as f: - f.write(result) - else: - pass +""") + +c = gpg.Context(armor=True) + +if len(sys.argv) >= 4: + keyfile = sys.argv[1] + logrus = sys.argv[2] + homedir = sys.argv[3] +elif len(sys.argv) == 3: + keyfile = sys.argv[1] + logrus = sys.argv[2] + homedir = input("Enter the GPG configuration directory path (optional): ") +elif len(sys.argv) == 2: + keyfile = sys.argv[1] + logrus = input("Enter the UID matching the key(s) to export: ") + homedir = input("Enter the GPG configuration directory path (optional): ") +else: + keyfile = input("Enter the path and filename to save the secret key to: ") + logrus = input("Enter the UID matching the key(s) to export: ") + homedir = input("Enter the GPG configuration directory path (optional): ") + +if homedir.startswith("~"): + if os.path.exists(os.path.expanduser(homedir)) is True: + c.home_dir = os.path.expanduser(homedir) + else: + pass +elif os.path.exists(homedir) is True: + c.home_dir = homedir +else: + pass + +try: + result = c.key_export(pattern=logrus) +except: + result = c.key_export(pattern=None) + +if result is not None: + with open(keyfile, "wb") as f: + f.write(result) +else: + pass #+end_src It is important to note that the result will only return =None= when a @@ -593,54 +593,54 @@ pattern has been entered for =logrus=, but it has not matched any keys. When the search pattern itself is set to =None= this triggers the exporting of the entire public keybox. -#+begin_src python - import gpg - import os.path - import sys - - print(""" - This script exports one or more public keys in minimised form. - """) - - c = gpg.Context(armor=True) - - if len(sys.argv) >= 4: - keyfile = sys.argv[1] - logrus = sys.argv[2] - homedir = sys.argv[3] - elif len(sys.argv) == 3: - keyfile = sys.argv[1] - logrus = sys.argv[2] - homedir = input("Enter the GPG configuration directory path (optional): ") - elif len(sys.argv) == 2: - keyfile = sys.argv[1] - logrus = input("Enter the UID matching the key(s) to export: ") - homedir = input("Enter the GPG configuration directory path (optional): ") - else: - keyfile = input("Enter the path and filename to save the secret key to: ") - logrus = input("Enter the UID matching the key(s) to export: ") - homedir = input("Enter the GPG configuration directory path (optional): ") - - if homedir.startswith("~"): - if os.path.exists(os.path.expanduser(homedir)) is True: - c.home_dir = os.path.expanduser(homedir) - else: - pass - elif os.path.exists(homedir) is True: - c.home_dir = homedir - else: - pass - - try: - result = c.key_export_minimal(pattern=logrus) - except: - result = c.key_export_minimal(pattern=None) - - if result is not None: - with open(keyfile, "wb") as f: - f.write(result) - else: - pass +#+begin_src python -i +import gpg +import os.path +import sys + +print(""" +This script exports one or more public keys in minimised form. +""") + +c = gpg.Context(armor=True) + +if len(sys.argv) >= 4: + keyfile = sys.argv[1] + logrus = sys.argv[2] + homedir = sys.argv[3] +elif len(sys.argv) == 3: + keyfile = sys.argv[1] + logrus = sys.argv[2] + homedir = input("Enter the GPG configuration directory path (optional): ") +elif len(sys.argv) == 2: + keyfile = sys.argv[1] + logrus = input("Enter the UID matching the key(s) to export: ") + homedir = input("Enter the GPG configuration directory path (optional): ") +else: + keyfile = input("Enter the path and filename to save the secret key to: ") + logrus = input("Enter the UID matching the key(s) to export: ") + homedir = input("Enter the GPG configuration directory path (optional): ") + +if homedir.startswith("~"): + if os.path.exists(os.path.expanduser(homedir)) is True: + c.home_dir = os.path.expanduser(homedir) + else: + pass +elif os.path.exists(homedir) is True: + c.home_dir = homedir +else: + pass + +try: + result = c.key_export_minimal(pattern=logrus) +except: + result = c.key_export_minimal(pattern=None) + +if result is not None: + with open(keyfile, "wb") as f: + f.write(result) +else: + pass #+end_src @@ -657,58 +657,58 @@ The following example exports the secret key to a file which is then set with the same permissions as the output files created by the command line secret key export options. -#+begin_src python - import gpg - import os - import os.path - import sys - - print(""" - This script exports one or more secret keys. - - The gpg-agent and pinentry are invoked to authorise the export. - """) - - c = gpg.Context(armor=True) - - if len(sys.argv) >= 4: - keyfile = sys.argv[1] - logrus = sys.argv[2] - homedir = sys.argv[3] - elif len(sys.argv) == 3: - keyfile = sys.argv[1] - logrus = sys.argv[2] - homedir = input("Enter the GPG configuration directory path (optional): ") - elif len(sys.argv) == 2: - keyfile = sys.argv[1] - logrus = input("Enter the UID matching the secret key(s) to export: ") - homedir = input("Enter the GPG configuration directory path (optional): ") - else: - keyfile = input("Enter the path and filename to save the secret key to: ") - logrus = input("Enter the UID matching the secret key(s) to export: ") - homedir = input("Enter the GPG configuration directory path (optional): ") - - if homedir.startswith("~"): - if os.path.exists(os.path.expanduser(homedir)) is True: - c.home_dir = os.path.expanduser(homedir) - else: - pass - elif os.path.exists(homedir) is True: - c.home_dir = homedir - else: - pass - - try: - result = c.key_export_secret(pattern=logrus) - except: - result = c.key_export_secret(pattern=None) - - if result is not None: - with open(keyfile, "wb") as f: - f.write(result) - os.chmod(keyfile, 0o600) - else: - pass +#+begin_src python -i +import gpg +import os +import os.path +import sys + +print(""" +This script exports one or more secret keys. + +The gpg-agent and pinentry are invoked to authorise the export. +""") + +c = gpg.Context(armor=True) + +if len(sys.argv) >= 4: + keyfile = sys.argv[1] + logrus = sys.argv[2] + homedir = sys.argv[3] +elif len(sys.argv) == 3: + keyfile = sys.argv[1] + logrus = sys.argv[2] + homedir = input("Enter the GPG configuration directory path (optional): ") +elif len(sys.argv) == 2: + keyfile = sys.argv[1] + logrus = input("Enter the UID matching the secret key(s) to export: ") + homedir = input("Enter the GPG configuration directory path (optional): ") +else: + keyfile = input("Enter the path and filename to save the secret key to: ") + logrus = input("Enter the UID matching the secret key(s) to export: ") + homedir = input("Enter the GPG configuration directory path (optional): ") + +if homedir.startswith("~"): + if os.path.exists(os.path.expanduser(homedir)) is True: + c.home_dir = os.path.expanduser(homedir) + else: + pass +elif os.path.exists(homedir) is True: + c.home_dir = homedir +else: + pass + +try: + result = c.key_export_secret(pattern=logrus) +except: + result = c.key_export_secret(pattern=None) + +if result is not None: + with open(keyfile, "wb") as f: + f.write(result) + os.chmod(keyfile, 0o600) +else: + pass #+end_src Alternatively the approach of the following script can be used. This @@ -718,91 +718,91 @@ readable and writable by the user. It also exports the secret key(s) twice in order to output both GPG binary (=.gpg=) and ASCII armoured (=.asc=) files. -#+begin_src python - import gpg - import os - import os.path - import subprocess - import sys - - print(""" - This script exports one or more secret keys as both ASCII armored and binary - file formats, saved in files within the user's GPG home directory. - - The gpg-agent and pinentry are invoked to authorise the export. - """) - - if sys.platform == "win32": - gpgconfcmd = "gpgconf.exe --list-dirs homedir" - else: - gpgconfcmd = "gpgconf --list-dirs homedir" - - a = gpg.Context(armor=True) - b = gpg.Context() - c = gpg.Context() - - if len(sys.argv) >= 4: - keyfile = sys.argv[1] - logrus = sys.argv[2] - homedir = sys.argv[3] - elif len(sys.argv) == 3: - keyfile = sys.argv[1] - logrus = sys.argv[2] - homedir = input("Enter the GPG configuration directory path (optional): ") - elif len(sys.argv) == 2: - keyfile = sys.argv[1] - logrus = input("Enter the UID matching the secret key(s) to export: ") - homedir = input("Enter the GPG configuration directory path (optional): ") - else: - keyfile = input("Enter the filename to save the secret key to: ") - logrus = input("Enter the UID matching the secret key(s) to export: ") - homedir = input("Enter the GPG configuration directory path (optional): ") - - if homedir.startswith("~"): - if os.path.exists(os.path.expanduser(homedir)) is True: - c.home_dir = os.path.expanduser(homedir) - else: - pass - elif os.path.exists(homedir) is True: - c.home_dir = homedir - else: - pass - - if c.home_dir is not None: - if c.home_dir.endswith("/"): - gpgfile = "{0}{1}.gpg".format(c.home_dir, keyfile) - ascfile = "{0}{1}.asc".format(c.home_dir, keyfile) - else: - gpgfile = "{0}/{1}.gpg".format(c.home_dir, keyfile) - ascfile = "{0}/{1}.asc".format(c.home_dir, keyfile) - else: - if os.path.exists(os.environ["GNUPGHOME"]) is True: - hd = os.environ["GNUPGHOME"] - else: - hd = subprocess.getoutput(gpgconfcmd) - gpgfile = "{0}/{1}.gpg".format(hd, keyfile) - ascfile = "{0}/{1}.asc".format(hd, keyfile) - - try: - a_result = a.key_export_secret(pattern=logrus) - b_result = b.key_export_secret(pattern=logrus) - except: - a_result = a.key_export_secret(pattern=None) - b_result = b.key_export_secret(pattern=None) - - if a_result is not None: - with open(ascfile, "wb") as f: - f.write(a_result) - os.chmod(ascfile, 0o600) - else: - pass - - if b_result is not None: - with open(gpgfile, "wb") as f: - f.write(b_result) - os.chmod(gpgfile, 0o600) - else: - pass +#+begin_src python -i +import gpg +import os +import os.path +import subprocess +import sys + +print(""" +This script exports one or more secret keys as both ASCII armored and binary +file formats, saved in files within the user's GPG home directory. + +The gpg-agent and pinentry are invoked to authorise the export. +""") + +if sys.platform == "win32": + gpgconfcmd = "gpgconf.exe --list-dirs homedir" +else: + gpgconfcmd = "gpgconf --list-dirs homedir" + +a = gpg.Context(armor=True) +b = gpg.Context() +c = gpg.Context() + +if len(sys.argv) >= 4: + keyfile = sys.argv[1] + logrus = sys.argv[2] + homedir = sys.argv[3] +elif len(sys.argv) == 3: + keyfile = sys.argv[1] + logrus = sys.argv[2] + homedir = input("Enter the GPG configuration directory path (optional): ") +elif len(sys.argv) == 2: + keyfile = sys.argv[1] + logrus = input("Enter the UID matching the secret key(s) to export: ") + homedir = input("Enter the GPG configuration directory path (optional): ") +else: + keyfile = input("Enter the filename to save the secret key to: ") + logrus = input("Enter the UID matching the secret key(s) to export: ") + homedir = input("Enter the GPG configuration directory path (optional): ") + +if homedir.startswith("~"): + if os.path.exists(os.path.expanduser(homedir)) is True: + c.home_dir = os.path.expanduser(homedir) + else: + pass +elif os.path.exists(homedir) is True: + c.home_dir = homedir +else: + pass + +if c.home_dir is not None: + if c.home_dir.endswith("/"): + gpgfile = "{0}{1}.gpg".format(c.home_dir, keyfile) + ascfile = "{0}{1}.asc".format(c.home_dir, keyfile) + else: + gpgfile = "{0}/{1}.gpg".format(c.home_dir, keyfile) + ascfile = "{0}/{1}.asc".format(c.home_dir, keyfile) +else: + if os.path.exists(os.environ["GNUPGHOME"]) is True: + hd = os.environ["GNUPGHOME"] + else: + hd = subprocess.getoutput(gpgconfcmd) + gpgfile = "{0}/{1}.gpg".format(hd, keyfile) + ascfile = "{0}/{1}.asc".format(hd, keyfile) + +try: + a_result = a.key_export_secret(pattern=logrus) + b_result = b.key_export_secret(pattern=logrus) +except: + a_result = a.key_export_secret(pattern=None) + b_result = b.key_export_secret(pattern=None) + +if a_result is not None: + with open(ascfile, "wb") as f: + f.write(a_result) + os.chmod(ascfile, 0o600) +else: + pass + +if b_result is not None: + with open(gpgfile, "wb") as f: + f.write(b_result) + os.chmod(gpgfile, 0o600) +else: + pass #+end_src @@ -850,24 +850,23 @@ trust model settings for recipient keys (defaults to =False=); =expect_sign=, prepare for signing (defaults to =False=); =compress=, compresses the plaintext prior to encryption (defaults to =True=). -#+begin_src python - import gpg +#+begin_src python -i +import gpg - a_key = "0x12345678DEADBEEF" - text = b"""Some text to test with. +a_key = "0x12345678DEADBEEF" +text = b"""Some text to test with. - Since the text in this case must be bytes, it is most likely that - the input form will be a separate file which is opened with "rb" - as this is the simplest method of obtaining the correct data - format. - """ +Since the text in this case must be bytes, it is most likely that +the input form will be a separate file which is opened with "rb" +as this is the simplest method of obtaining the correct data format. +""" - c = gpg.Context(armor=True) - rkey = list(c.keylist(pattern=a_key, secret=False)) - ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=False) +c = gpg.Context(armor=True) +rkey = list(c.keylist(pattern=a_key, secret=False)) +ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=False) - with open("secret_plans.txt.asc", "wb") as afile: - afile.write(ciphertext) +with open("secret_plans.txt.asc", "wb") as afile: + afile.write(ciphertext) #+end_src Though this is even more likely to be used like this; with the @@ -875,22 +874,22 @@ plaintext input read from a file, the recipient keys used for encryption regardless of key trust status and the encrypted output also encrypted to any preconfigured keys set in the =gpg.conf= file: -#+begin_src python - import gpg +#+begin_src python -i +import gpg - a_key = "0x12345678DEADBEEF" +a_key = "0x12345678DEADBEEF" - with open("secret_plans.txt", "rb") as afile: - text = afile.read() +with open("secret_plans.txt", "rb") as afile: + text = afile.read() - c = gpg.Context(armor=True) - rkey = list(c.keylist(pattern=a_key, secret=False)) - ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=True, - always_trust=True, - add_encrypt_to=True) +c = gpg.Context(armor=True) +rkey = list(c.keylist(pattern=a_key, secret=False)) +ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=True, + always_trust=True, + add_encrypt_to=True) - with open("secret_plans.txt.asc", "wb") as afile: - afile.write(ciphertext) +with open("secret_plans.txt.asc", "wb") as afile: + afile.write(ciphertext) #+end_src If the =recipients= paramater is empty then the plaintext is encrypted @@ -912,45 +911,45 @@ email address on the =gnupg.org= domain,[fn:3] but does /not/ encrypt to a default key or other key which is configured to normally encrypt to. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - text = b"""Oh look, another test message. +text = b"""Oh look, another test message. - The same rules apply as with the previous example and more likely - than not, the message will actually be drawn from reading the - contents of a file or, maybe, from entering data at an input() - prompt. +The same rules apply as with the previous example and more likely +than not, the message will actually be drawn from reading the +contents of a file or, maybe, from entering data at an input() +prompt. - Since the text in this case must be bytes, it is most likely that - the input form will be a separate file which is opened with "rb" - as this is the simplest method of obtaining the correct data - format. - """ +Since the text in this case must be bytes, it is most likely that +the input form will be a separate file which is opened with "rb" +as this is the simplest method of obtaining the correct data +format. +""" - c = gpg.Context(armor=True) - rpattern = list(c.keylist(pattern="@gnupg.org", secret=False)) - logrus = [] +c = gpg.Context(armor=True) +rpattern = list(c.keylist(pattern="@gnupg.org", secret=False)) +logrus = [] - for i in range(len(rpattern)): - if rpattern[i].can_encrypt == 1: - logrus.append(rpattern[i]) +for i in range(len(rpattern)): + if rpattern[i].can_encrypt == 1: + logrus.append(rpattern[i]) - ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, - sign=False, always_trust=True) +ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, + sign=False, always_trust=True) - with open("secret_plans.txt.asc", "wb") as afile: - afile.write(ciphertext) +with open("secret_plans.txt.asc", "wb") as afile: + afile.write(ciphertext) #+end_src All it would take to change the above example to sign the message and also encrypt the message to any configured default keys would be to change the =c.encrypt= line to this: -#+begin_src python - ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, - always_trust=True, - add_encrypt_to=True) +#+begin_src python -i +ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, + always_trust=True, + add_encrypt_to=True) #+end_src The only keyword arguments requiring modification are those for which @@ -963,38 +962,38 @@ are not trusted (e.g. not signed or locally signed) then the encryption will raise an error. It is possible to mitigate this somewhat with something more like this: -#+begin_src python - import gpg - - with open("secret_plans.txt.asc", "rb") as afile: - text = afile.read() - - c = gpg.Context(armor=True) - rpattern = list(c.keylist(pattern="@gnupg.org", secret=False)) - logrus = [] - - for i in range(len(rpattern)): - if rpattern[i].can_encrypt == 1: - logrus.append(rpattern[i]) - - try: - ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, - add_encrypt_to=True) - except gpg.errors.InvalidRecipients as e: - for i in range(len(e.recipients)): - for n in range(len(logrus)): - if logrus[n].fpr == e.recipients[i].fpr: - logrus.remove(logrus[n]) - else: - pass - try: - ciphertext, result, sign_result = c.encrypt(text, - recipients=logrus, - add_encrypt_to=True) - with open("secret_plans.txt.asc", "wb") as afile: - afile.write(ciphertext) - except: - pass +#+begin_src python -i +import gpg + +with open("secret_plans.txt.asc", "rb") as afile: + text = afile.read() + +c = gpg.Context(armor=True) +rpattern = list(c.keylist(pattern="@gnupg.org", secret=False)) +logrus = [] + +for i in range(len(rpattern)): + if rpattern[i].can_encrypt == 1: + logrus.append(rpattern[i]) + + try: + ciphertext, result, sign_result = c.encrypt(text, recipients=logrus, + add_encrypt_to=True) + except gpg.errors.InvalidRecipients as e: + for i in range(len(e.recipients)): + for n in range(len(logrus)): + if logrus[n].fpr == e.recipients[i].fpr: + logrus.remove(logrus[n]) + else: + pass + try: + ciphertext, result, sign_result = c.encrypt(text, + recipients=logrus, + add_encrypt_to=True) + with open("secret_plans.txt.asc", "wb") as afile: + afile.write(ciphertext) + except: + pass #+end_src This will attempt to encrypt to all the keys searched for, then remove @@ -1015,24 +1014,24 @@ to modify the Context prior to conducting the decryption and since the Context is only used once, setting it to =c= simply adds lines for no gain. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - ciphertext = input("Enter path and filename of encrypted file: ") - newfile = input("Enter path and filename of file to save decrypted data to: ") +ciphertext = input("Enter path and filename of encrypted file: ") +newfile = input("Enter path and filename of file to save decrypted data to: ") - with open(ciphertext, "rb") as cfile: - try: - plaintext, result, verify_result = gpg.Context().decrypt(cfile) - except gpg.errors.GPGMEError as e: - plaintext = None - print(e) +with open(ciphertext, "rb") as cfile: + try: + plaintext, result, verify_result = gpg.Context().decrypt(cfile) + except gpg.errors.GPGMEError as e: + plaintext = None + print(e) - if plaintext is not None: - with open(newfile, "wb") as nfile: - nfile.write(plaintext) - else: - pass + if plaintext is not None: + with open(newfile, "wb") as nfile: + nfile.write(plaintext) + else: + pass #+end_src The data available in =plaintext= in this example is the decrypted @@ -1060,12 +1059,12 @@ default key specified and there is more than one secret key available it may be necessary to specify the key or keys with which to sign messages and files. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - logrus = input("Enter the email address or string to match signing keys to: ") - hancock = gpg.Context().keylist(pattern=logrus, secret=True) - sig_src = list(hancock) +logrus = input("Enter the email address or string to match signing keys to: ") +hancock = gpg.Context().keylist(pattern=logrus, secret=True) +sig_src = list(hancock) #+end_src The signing examples in the following sections include the explicitly @@ -1101,19 +1100,19 @@ multiple keys are involved; from the preferences saved into the key itself or by comparison with the preferences with all other keys involved. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - text0 = """Declaration of ... something. +text0 = """Declaration of ... something. - """ - text = text0.encode() +""" +text = text0.encode() - c = gpg.Context(armor=True, signers=sig_src) - signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.NORMAL) +c = gpg.Context(armor=True, signers=sig_src) +signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.NORMAL) - with open("/path/to/statement.txt.asc", "w") as afile: - afile.write(signed_data.decode()) +with open("/path/to/statement.txt.asc", "w") as afile: + afile.write(signed_data.decode()) #+end_src Though everything in this example is accurate, it is more likely that @@ -1121,17 +1120,17 @@ reading the input data from another file and writing the result to a new file will be performed more like the way it is done in the next example. Even if the output format is ASCII armoured. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - with open("/path/to/statement.txt", "rb") as tfile: - text = tfile.read() +with open("/path/to/statement.txt", "rb") as tfile: + text = tfile.read() - c = gpg.Context() - signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.NORMAL) +c = gpg.Context() +signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.NORMAL) - with open("/path/to/statement.txt.sig", "wb") as afile: - afile.write(signed_data) +with open("/path/to/statement.txt.sig", "wb") as afile: + afile.write(signed_data) #+end_src @@ -1144,35 +1143,35 @@ Detached signatures will often be needed in programmatic uses of GPGME, either for signing files (e.g. tarballs of code releases) or as a component of message signing (e.g. PGP/MIME encoded email). -#+begin_src python - import gpg +#+begin_src python -i +import gpg - text0 = """Declaration of ... something. +text0 = """Declaration of ... something. - """ - text = text0.encode() +""" +text = text0.encode() - c = gpg.Context(armor=True) - signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.DETACH) +c = gpg.Context(armor=True) +signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.DETACH) - with open("/path/to/statement.txt.asc", "w") as afile: - afile.write(signed_data.decode()) +with open("/path/to/statement.txt.asc", "w") as afile: + afile.write(signed_data.decode()) #+end_src As with normal signatures, detached signatures are best handled as byte literals, even when the output is ASCII armoured. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - with open("/path/to/statement.txt", "rb") as tfile: - text = tfile.read() +with open("/path/to/statement.txt", "rb") as tfile: + text = tfile.read() - c = gpg.Context(signers=sig_src) - signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.DETACH) +c = gpg.Context(signers=sig_src) +signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.DETACH) - with open("/path/to/statement.txt.sig", "wb") as afile: - afile.write(signed_data) +with open("/path/to/statement.txt.sig", "wb") as afile: + afile.write(signed_data) #+end_src @@ -1185,35 +1184,35 @@ Though PGP/in-line messages are no longer encouraged in favour of PGP/MIME, there is still sometimes value in utilising in-line signatures. This is where clear-signed messages or text is of value. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - text0 = """Declaration of ... something. +text0 = """Declaration of ... something. - """ - text = text0.encode() +""" +text = text0.encode() - c = gpg.Context() - signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR) +c = gpg.Context() +signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR) - with open("/path/to/statement.txt.asc", "w") as afile: - afile.write(signed_data.decode()) +with open("/path/to/statement.txt.asc", "w") as afile: + afile.write(signed_data.decode()) #+end_src In spite of the appearance of a clear-signed message, the data handled by GPGME in signing it must still be byte literals. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - with open("/path/to/statement.txt", "rb") as tfile: - text = tfile.read() +with open("/path/to/statement.txt", "rb") as tfile: + text = tfile.read() - c = gpg.Context() - signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR) +c = gpg.Context() +signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR) - with open("/path/to/statement.txt.asc", "wb") as afile: - afile.write(signed_data) +with open("/path/to/statement.txt.asc", "wb") as afile: + afile.write(signed_data) #+end_src @@ -1230,79 +1229,79 @@ with files and data with detached signatures. The following example is intended for use with the default signing method where the file was not ASCII armoured: -#+begin_src python - import gpg - import time - - filename = "statement.txt" - gpg_file = "statement.txt.gpg" - - c = gpg.Context() - - try: - data, result = c.verify(open(gpg_file)) - verified = True - except gpg.errors.BadSignatures as e: - verified = False - print(e) - - if verified is True: - for i in range(len(result.signatures)): - sign = result.signatures[i] - print("""Good signature from: - {0} - with key {1} - made at {2} - """.format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, - time.ctime(sign.timestamp))) - else: - pass +#+begin_src python -i +import gpg +import time + +filename = "statement.txt" +gpg_file = "statement.txt.gpg" + +c = gpg.Context() + +try: + data, result = c.verify(open(gpg_file)) + verified = True +except gpg.errors.BadSignatures as e: + verified = False + print(e) + +if verified is True: + for i in range(len(result.signatures)): + sign = result.signatures[i] + print("""Good signature from: +{0} +with key {1} +made at {2} +""".format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, + time.ctime(sign.timestamp))) +else: + pass #+end_src Whereas this next example, which is almost identical would work with normal ASCII armoured files and with clear-signed files: -#+begin_src python - import gpg - import time - - filename = "statement.txt" - asc_file = "statement.txt.asc" - - c = gpg.Context() - - try: - data, result = c.verify(open(asc_file)) - verified = True - except gpg.errors.BadSignatures as e: - verified = False - print(e) - - if verified is True: - for i in range(len(result.signatures)): - sign = result.signatures[i] - print("""Good signature from: - {0} - with key {1} - made at {2} - """.format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, - time.ctime(sign.timestamp))) - else: - pass +#+begin_src python -i +import gpg +import time + +filename = "statement.txt" +asc_file = "statement.txt.asc" + +c = gpg.Context() + +try: + data, result = c.verify(open(asc_file)) + verified = True +except gpg.errors.BadSignatures as e: + verified = False + print(e) + +if verified is True: + for i in range(len(result.signatures)): + sign = result.signatures[i] + print("""Good signature from: +{0} +with key {1} +made at {2} +""".format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, + time.ctime(sign.timestamp))) +else: + pass #+end_src In both of the previous examples it is also possible to compare the original data that was signed against the signed data in =data= to see if it matches with something like this: -#+begin_src python - with open(filename, "rb") as afile: - text = afile.read() +#+begin_src python -i +with open(filename, "rb") as afile: + text = afile.read() - if text == data: - print("Good signature.") - else: - pass +if text == data: + print("Good signature.") +else: + pass #+end_src The following two examples, however, deal with detached signatures. @@ -1311,62 +1310,62 @@ returned since it is already being explicitly referenced in the first argument of =c.verify=. So =data= is =None= and only the information in =result= is available. -#+begin_src python - import gpg - import time - - filename = "statement.txt" - sig_file = "statement.txt.sig" - - c = gpg.Context() - - try: - data, result = c.verify(open(filename), open(sig_file)) - verified = True - except gpg.errors.BadSignatures as e: - verified = False - print(e) - - if verified is True: - for i in range(len(result.signatures)): - sign = result.signatures[i] - print("""Good signature from: - {0} - with key {1} - made at {2} - """.format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, - time.ctime(sign.timestamp))) - else: - pass +#+begin_src python -i +import gpg +import time + +filename = "statement.txt" +sig_file = "statement.txt.sig" + +c = gpg.Context() + +try: + data, result = c.verify(open(filename), open(sig_file)) + verified = True +except gpg.errors.BadSignatures as e: + verified = False + print(e) + +if verified is True: + for i in range(len(result.signatures)): + sign = result.signatures[i] + print("""Good signature from: +{0} +with key {1} +made at {2} +""".format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, + time.ctime(sign.timestamp))) +else: + pass #+end_src -#+begin_src python - import gpg - import time - - filename = "statement.txt" - asc_file = "statement.txt.asc" - - c = gpg.Context() - - try: - data, result = c.verify(open(filename), open(asc_file)) - verified = True - except gpg.errors.BadSignatures as e: - verified = False - print(e) - - if verified is True: - for i in range(len(result.signatures)): - sign = result.signatures[i] - print("""Good signature from: - {0} - with key {1} - made at {2} - """.format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, - time.ctime(sign.timestamp))) - else: - pass +#+begin_src python -i +import gpg +import time + +filename = "statement.txt" +asc_file = "statement.txt.asc" + +c = gpg.Context() + +try: + data, result = c.verify(open(filename), open(asc_file)) + verified = True +except gpg.errors.BadSignatures as e: + verified = False + print(e) + +if verified is True: + for i in range(len(result.signatures)): + sign = result.signatures[i] + print("""Good signature from: +{0} +with key {1} +made at {2} +""".format(c.get_key(sign.fpr).uids[0].uid, sign.fpr, + time.ctime(sign.timestamp))) +else: + pass #+end_src @@ -1424,16 +1423,16 @@ be the passphrase and if =passphrase= is set to =True= then gpg-agent will launch pinentry to prompt for a passphrase. For the sake of convenience, these examples will keep =passphrase= set to =None=. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - c = gpg.Context() +c = gpg.Context() - c.home_dir = "~/.gnupg-dm" - userid = "Danger Mouse " +c.home_dir = "~/.gnupg-dm" +userid = "Danger Mouse " - dmkey = c.create_key(userid, algorithm="rsa3072", expires_in=31536000, - sign=True, certify=True) +dmkey = c.create_key(userid, algorithm="rsa3072", expires_in=31536000, + sign=True, certify=True) #+end_src One thing to note here is the use of setting the =c.home_dir= @@ -1452,8 +1451,8 @@ already set and the correct directory and file permissions. The successful generation of the key can be confirmed via the returned =GenkeyResult= object, which includes the following data: -#+begin_src python - print(""" +#+begin_src python -i +print(""" Fingerprint: {0} Primary Key: {1} Public Key: {2} @@ -1519,21 +1518,21 @@ primary key. Since Danger Mouse is a security conscious secret agent, this subkey will only be valid for about six months, half the length of the primary key. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - c = gpg.Context() - c.home_dir = "~/.gnupg-dm" +c = gpg.Context() +c.home_dir = "~/.gnupg-dm" - key = c.get_key(dmkey.fpr, secret=True) - dmsub = c.create_subkey(key, algorithm="rsa3072", expires_in=15768000, - encrypt=True) +key = c.get_key(dmkey.fpr, secret=True) +dmsub = c.create_subkey(key, algorithm="rsa3072", expires_in=15768000, + encrypt=True) #+end_src As with the primary key, the results here can be checked with: -#+begin_src python - print(""" +#+begin_src python -i +print(""" Fingerprint: {0} Primary Key: {1} Public Key: {2} @@ -1575,17 +1574,17 @@ ID to an existing key is much simpler. The method used to do this is =key_add_uid= and the only arguments it takes are for the =key= and the new =uid=. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - c = gpg.Context() - c.home_dir = "~/.gnupg-dm" +c = gpg.Context() +c.home_dir = "~/.gnupg-dm" - dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" - key = c.get_key(dmfpr, secret=True) - uid = "Danger Mouse " +dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" +key = c.get_key(dmfpr, secret=True) +uid = "Danger Mouse " - c.key_add_uid(key, uid) +c.key_add_uid(key, uid) #+end_src Unsurprisingly the result of this is: @@ -1612,17 +1611,17 @@ Unsurprisingly the result of this is: Revoking a user ID is a fairly similar process, except that it uses the =key_revoke_uid= method. -#+begin_src python - import gpg +#+begin_src python -i +import gpg - c = gpg.Context() - c.home_dir = "~/.gnupg-dm" +c = gpg.Context() +c.home_dir = "~/.gnupg-dm" - dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" - key = c.get_key(dmfpr, secret=True) - uid = "Danger Mouse " +dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" +key = c.get_key(dmfpr, secret=True) +uid = "Danger Mouse " - c.key_revoke_uid(key, uid) +c.key_revoke_uid(key, uid) #+end_src @@ -1652,15 +1651,15 @@ it is case sensitive. To sign Danger Mouse's key for just the initial user ID with a signature which will last a little over a month, do this: -#+begin_src python - import gpg +#+begin_src python -i +import gpg - c = gpg.Context() - uid = "Danger Mouse " +c = gpg.Context() +uid = "Danger Mouse " - dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" - key = c.get_key(dmfpr, secret=True) - c.key_sign(key, uids=uid, expires_in=2764800) +dmfpr = "177B7C25DB99745EE2EE13ED026D2F19E99E63AA" +key = c.get_key(dmfpr, secret=True) +c.key_sign(key, uids=uid, expires_in=2764800) #+end_src @@ -1683,28 +1682,28 @@ MUAs readily. The following code, however, provides a work-around for obtaining this information in Python. -#+begin_src python - import subprocess +#+begin_src python -i +import subprocess - lines = subprocess.getoutput("gpgconf --list-options gpg").splitlines() +lines = subprocess.getoutput("gpgconf --list-options gpg").splitlines() - for i in range(len(lines)): - if lines[i].startswith("group") is True: - line = lines[i] - else: - pass +for i in range(len(lines)): + if lines[i].startswith("group") is True: + line = lines[i] + else: + pass - groups = line.split(":")[-1].replace('"', '').split(',') +groups = line.split(":")[-1].replace('"', '').split(',') - group_lines = [] - group_lists = [] +group_lines = [] +group_lists = [] - for i in range(len(groups)): - group_lines.append(groups[i].split("=")) - group_lists.append(groups[i].split("=")) +for i in range(len(groups)): + group_lines.append(groups[i].split("=")) + group_lists.append(groups[i].split("=")) - for i in range(len(group_lists)): - group_lists[i][1] = group_lists[i][1].split() +for i in range(len(group_lists)): + group_lists[i][1] = group_lists[i][1].split() #+end_src The result of that code is that =group_lines= is a list of lists where commit b47e1bb98a8ff93cae560449bfa9103c47f4d4f8 Author: Ben McGinnes Date: Sun Jul 22 21:20:41 2018 +1000 doc: python bindings howto * Added org-mode byline. diff --git a/lang/python/docs/GPGMEpythonHOWTOen.org b/lang/python/docs/GPGMEpythonHOWTOen.org index 106b624..df37226 100644 --- a/lang/python/docs/GPGMEpythonHOWTOen.org +++ b/lang/python/docs/GPGMEpythonHOWTOen.org @@ -1,4 +1,5 @@ #+TITLE: GNU Privacy Guard (GnuPG) Made Easy Python Bindings HOWTO (English) +#+AUTHOR: Ben McGinnes #+LATEX_COMPILER: xelatex #+LATEX_CLASS: article #+LATEX_CLASS_OPTIONS: [12pt] ----------------------------------------------------------------------- Summary of changes: lang/python/docs/GPGMEpythonHOWTOen.org | 1381 +++++++++++++++---------------- 1 file changed, 690 insertions(+), 691 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 23 14:51:42 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Mon, 23 Jul 2018 14:51:42 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-106-g26d222d Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via 26d222dfd48c4726d2699a9ec40df5dd6ecafe1f (commit) via bf3ed229470a0c4691e3cb06855ba24caaa99008 (commit) via 2a4f79650b1e1876f71ec9c7a5d9dfa95a3a293c (commit) via f4c21ec09d8451294a3137532bde7ae77993e34c (commit) via c1085f44e1771bacf5fca24faca9c45cc6f7bd35 (commit) via efaddd81771b267b155595df4f43d3e1b72cd100 (commit) via b881eebb0d89e7ce000b01a96c35d137ba558509 (commit) via 1020ddceb349e508cadcae8155708bd3d5937aa9 (commit) via dff52c1a96c4b28ee2c5f66493d19507dacda5ca (commit) via 9dfe1f112bc5da8d5b2240547c8fcc2751ff895b (commit) via 945d6a7dd8841c40bfe5986baa4a0d65c26f9c6b (commit) from a9c34f58409c799ef22289d3bcf64b87866997c6 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 26d222dfd48c4726d2699a9ec40df5dd6ecafe1f Author: Andre Heinecke Date: Mon Jul 23 14:01:16 2018 +0200 Poor redmond man's valgrind * src: Use x functions * src/xmalloc.h: Provide macros for memdbg. diff --git a/src/common.cpp b/src/common.cpp index 0f585eb..f3f41af 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -188,7 +188,7 @@ readRegStr (const char *root, const char *dir, const char *name) /* Return a string from the Win32 Registry or NULL in case of error. Caller must release the return value. A NULL for root is an alias for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. NOTE: The value - is allocated with a plain malloc() - use free() and not the usual + is allocated with a plain xmalloc () - use xfree () and not the usual xfree(). */ char * read_w32_registry_string (const char *root, const char *dir, const char *name) @@ -215,10 +215,10 @@ get_data_dir (void) /* Build the key: "/share/gpgol". */ #define SDDIR "\\share\\gpgol" - dname = (char*) malloc (strlen (instdir) + strlen (SDDIR) + 1); + dname = (char*) xmalloc (strlen (instdir) + strlen (SDDIR) + 1); if (!dname) { - free (instdir); + xfree (instdir); return NULL; } p = dname; @@ -226,7 +226,7 @@ get_data_dir (void) p += strlen (instdir); strcpy (p, SDDIR); - free (instdir); + xfree (instdir); #undef SDDIR return dname; @@ -246,7 +246,7 @@ percent_escape (const char *str, const char *extra) for (i=j=0; str[i]; i++) if (str[i] == ':' || str[i] == '%' || (extra && strchr (extra, str[i]))) j++; - ptr = (char *) malloc (i + 2 * j + 1); + ptr = (char *) xmalloc (i + 2 * j + 1); i = 0; while (*str) { @@ -762,6 +762,7 @@ gpgol_bug (HWND parent, int code) "or ask your Administrator for support."); char *with_code; gpgrt_asprintf (&with_code, "%s\nCode: %i", bugmsg, code); + memdbg_alloc (with_code); gpgol_message_box (parent, with_code, _("GpgOL Error"), MB_OK); @@ -895,6 +896,7 @@ store_extension_subkey_value (const char *subkey, int ret; char *path; gpgrt_asprintf (&path, "%s\\%s", GPGOL_REGPATH, subkey); + memdbg_alloc (path); ret = store_config_value (HKEY_CURRENT_USER, path, key, val); xfree (path); return ret; diff --git a/src/common_indep.c b/src/common_indep.c index 046def8..c0fe91f 100644 --- a/src/common_indep.c +++ b/src/common_indep.c @@ -68,7 +68,7 @@ out_of_core (void) } void* -xmalloc (size_t n) +_xmalloc (size_t n) { void *p = malloc (n); if (!p) @@ -77,7 +77,7 @@ xmalloc (size_t n) } void* -xcalloc (size_t m, size_t n) +_xcalloc (size_t m, size_t n) { void *p = calloc (m, n); if (!p) @@ -86,7 +86,7 @@ xcalloc (size_t m, size_t n) } void * -xrealloc (void *a, size_t n) +_xrealloc (void *a, size_t n) { void *p = realloc (a, n); if (!p) @@ -95,15 +95,26 @@ xrealloc (void *a, size_t n) } char* -xstrdup (const char *s) +_xstrdup (const char *s) { - char *p = xmalloc (strlen (s)+1); + char *p = _xmalloc (strlen (s)+1); strcpy (p, s); return p; } +wchar_t* +_xwcsdup (const wchar_t *s) +{ + wchar_t *p = wcsdup (s); + if (!s) + { + out_of_core (); + } + return p; +} + void -xfree (void *p) +_xfree (void *p) { if (p) free (p); diff --git a/src/cpphelp.cpp b/src/cpphelp.cpp index 5912f81..a7a57ad 100644 --- a/src/cpphelp.cpp +++ b/src/cpphelp.cpp @@ -42,7 +42,9 @@ release_cArray (char **carray) if (carray) { for (int idx = 0; carray[idx]; idx++) - xfree (carray[idx]); + { + xfree (carray[idx]); + } xfree (carray); } } diff --git a/src/filetype.c b/src/filetype.c index c59dde7..1059daa 100644 --- a/src/filetype.c +++ b/src/filetype.c @@ -25,6 +25,7 @@ #include "parsetlv.h" #include "filetype.h" +#include "common_indep.h" /* The size of the buffer we use to identify CMS objects. */ @@ -107,7 +108,7 @@ is_cms_file (const char *fname) if (!fp) return 0; /* Not found - can't be a CMS file. */ - data = malloc (CMS_BUFFER_SIZE); + data = xmalloc (CMS_BUFFER_SIZE); if (!data) { fclose (fp); @@ -119,7 +120,7 @@ is_cms_file (const char *fname) fclose (fp); result = detect_cms (data, datalen); - free (data); + xfree (data); return result; } @@ -138,13 +139,13 @@ is_cms_data (const char *data, size_t datalen) if (datalen > CMS_BUFFER_SIZE - 1) datalen = CMS_BUFFER_SIZE - 1; - buffer = malloc (datalen + 1); + buffer = xmalloc (datalen + 1); if (!buffer) return 0; /* Oops */ memcpy (buffer, data, datalen); buffer[datalen] = 0; result = detect_cms (buffer, datalen); - free (buffer); + xfree (buffer); return result; } diff --git a/src/gpgoladdin.cpp b/src/gpgoladdin.cpp index 5adfb20..cf58167 100644 --- a/src/gpgoladdin.cpp +++ b/src/gpgoladdin.cpp @@ -1069,6 +1069,7 @@ GetCustomUI_MIME (BSTR RibbonID, BSTR * RibbonXml) if (buffer) { + memdbg_alloc (buffer); wchar_t *wbuf = utf8_to_wchar (buffer); xfree (buffer); *RibbonXml = SysAllocString (wbuf); diff --git a/src/mail.cpp b/src/mail.cpp index 0836bba..a03a7d9 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -903,6 +903,7 @@ do_crypt (LPVOID arg) char *buf = nullptr; gpgrt_asprintf (&buf, _("Crypto operation failed:\n%s"), err.asString()); + memdbg_alloc (buf); gpgol_message_box (mail->getWindow (), buf, _("GpgOL"), MB_OK); xfree (buf); } @@ -1037,6 +1038,7 @@ Mail::decryptVerify_o () SRCNAME, __func__); } } + memdbg_alloc (placeholder_buf); xfree (placeholder_buf); /* Do the actual parsing */ @@ -1837,6 +1839,7 @@ Mail::getRecipients_o () const "or ask your Administrator for support."); char *buf; gpgrt_asprintf (&buf, "Failed to resolve recipients.\n\n%s\n", bugmsg); + memdbg_alloc (buf); gpgol_message_box (get_active_hwnd (), buf, _("GpgOL"), MB_OK); @@ -2462,6 +2465,7 @@ Mail::getCryptoDetails_o () /* Level three is the only level for trusted S/MIME keys. */ gpgrt_asprintf (&buf, _("The senders identity is certified by the trusted issuer:\n'%s'\n"), m_sig.key().issuerName()); + memdbg_alloc (buf); message = buf; xfree (buf); } @@ -2488,6 +2492,7 @@ Mail::getCryptoDetails_o () "You encrypted %i and verified %i messages since."), time, m_uid.tofuInfo().encrCount(), m_uid.tofuInfo().signCount ()); + memdbg_alloc (buf); xfree (time); message = buf; xfree (buf); @@ -2510,6 +2515,7 @@ Mail::getCryptoDetails_o () "it since %s."), m_uid.tofuInfo().signCount (), m_uid.tofuInfo().encrCount (), time); + memdbg_alloc (buf); xfree (time); message = buf; xfree (buf); @@ -2587,6 +2593,7 @@ Mail::getCryptoDetails_o () { gpgrt_asprintf (&buf, _("does not claim the address: \"%s\"."), getSender_o ().c_str()); + memdbg_alloc (buf); message += buf; xfree (buf); } diff --git a/src/mailitem-events.cpp b/src/mailitem-events.cpp index 09a9fea..f93b239 100644 --- a/src/mailitem-events.cpp +++ b/src/mailitem-events.cpp @@ -315,6 +315,7 @@ EVENT_SINK_INVOKE(MailItemEvents) "message is not open in any window and not selected in the " "messagelist.\n\nFor example by right clicking but not selecting the message.\n"), wchar_to_utf8(prop_name)); + memdbg_alloc (fmt); wchar_t *msg = utf8_to_wchar (fmt); xfree (fmt); MessageBoxW (get_active_hwnd(), msg, title, diff --git a/src/main.c b/src/main.c index 5b6cdb7..43a34f4 100644 --- a/src/main.c +++ b/src/main.c @@ -88,16 +88,19 @@ get_gpgme_w32_inst_dir (void) char *gpg4win_dir = get_gpg4win_dir (); char *tmp; gpgrt_asprintf (&tmp, "%s\\bin\\gpgme-w32spawn.exe", gpg4win_dir); + memdbg_alloc (tmp); if (!access(tmp, R_OK)) { xfree (tmp); gpgrt_asprintf (&tmp, "%s\\bin", gpg4win_dir); + memdbg_alloc (tmp); xfree (gpg4win_dir); return tmp; } xfree (tmp); gpgrt_asprintf (&tmp, "%s\\gpgme-w32spawn.exe", gpg4win_dir); + memdbg_alloc (tmp); if (!access(tmp, R_OK)) { @@ -157,10 +160,10 @@ get_locale_dir (void) /* Build the key: "/share/locale". */ #define SLDIR "\\share\\locale" - dname = malloc (strlen (instdir) + strlen (SLDIR) + 1); + dname = xmalloc (strlen (instdir) + strlen (SLDIR) + 1); if (!dname) { - free (instdir); + xfree (instdir); return NULL; } p = dname; @@ -168,7 +171,7 @@ get_locale_dir (void) p += strlen (instdir); strcpy (p, SLDIR); - free (instdir); + xfree (instdir); return dname; } @@ -177,7 +180,7 @@ get_locale_dir (void) static void drop_locale_dir (char *locale_dir) { - free (locale_dir); + xfree (locale_dir); } @@ -253,7 +256,9 @@ read_options (void) after using the configuration dialog. */ store_extension_value ("enableDebug", "0"); } - xfree (val); val = NULL; + /* Yes we use free here because memtracing did not track the alloc + as the option for debuging was not read before. */ + free (val); val = NULL; if (opt.enable_debug) log_debug ("enabled debug flags:%s%s%s%s%s%s%s%s%s%s\n", (opt.enable_debug & DBG_IOWORKER)? " ioworker":"", diff --git a/src/mapihelp.cpp b/src/mapihelp.cpp index 301f692..abf94a6 100644 --- a/src/mapihelp.cpp +++ b/src/mapihelp.cpp @@ -112,7 +112,7 @@ create_gpgol_tag (LPMESSAGE message, const wchar_t *name, const char *func) HRESULT hr; LPSPropTagArray proparr = NULL; MAPINAMEID mnid, *pmnid; - wchar_t *propname = wcsdup (name); + wchar_t *propname = xwcsdup (name); /* {31805ab8-3e92-11dc-879c-00061b031004}: GpgOL custom properties. */ GUID guid = {0x31805ab8, 0x3e92, 0x11dc, {0x87, 0x9c, 0x00, 0x06, 0x1b, 0x03, 0x10, 0x04}}; diff --git a/src/memdbg.cpp b/src/memdbg.cpp index aabf2a8..cb39e62 100644 --- a/src/memdbg.cpp +++ b/src/memdbg.cpp @@ -33,6 +33,7 @@ std::map cppObjs; std::map olObjs; std::map olNames; +std::map allocs; GPGRT_LOCK_DEFINE (memdbg_log); @@ -213,7 +214,67 @@ memdbg_dtor (const char *objName) SRCNAME, __func__, nameStr.c_str()); } gpgrt_lock_unlock (&memdbg_log); +} + + +void +_memdbg_alloc (void *ptr, const char *srcname, const char *func, int line) +{ + DBGGUARD; + + if (!ptr) + { + TRACEPOINT; + return; + } + + gpgrt_lock_lock (&memdbg_log); + + const std::string identifier = std::string (srcname) + std::string (":") + + std::string (func) + std::string (":") + + std::to_string (line); + + auto it = allocs.find (ptr); + + if (it != allocs.end()) + { + TRACEPOINT; + gpgrt_lock_unlock (&memdbg_log); + return; + } + allocs.insert (std::make_pair (ptr, identifier)); + + gpgrt_lock_unlock (&memdbg_log); +} + + +int +memdbg_free (void *ptr) +{ + DBGGUARD false; + + if (!ptr) + { + TRACEPOINT; + return false; + } + + gpgrt_lock_lock (&memdbg_log); + + auto it = allocs.find (ptr); + if (it == allocs.end()) + { + log_error ("%s:%s Free unregistered: %p", + SRCNAME, __func__, ptr); + gpgrt_lock_unlock (&memdbg_log); + return false; + } + + allocs.erase (it); + + gpgrt_lock_unlock (&memdbg_log); + return true; } void @@ -249,6 +310,12 @@ memdbg_dump () } } log_debug("-- OL End --"); + log_debug("-- Allocated Addresses --"); + for (const auto &pair: allocs) + { + log_debug ("%s: %p", pair.second.c_str(), pair.first); + } + log_debug("-- Allocated Addresses End --"); log_debug("" "------------------------------MEMORY END ----------------------------------"); diff --git a/src/memdbg.h b/src/memdbg.h index 49e34c1..aa4939d 100644 --- a/src/memdbg.h +++ b/src/memdbg.h @@ -45,6 +45,11 @@ void memdbg_released (void *obj); void memdbg_ctor (const char *objName); void memdbg_dtor (const char *objName); +void _memdbg_alloc (void *ptr, const char *srcname, const char *func, int line); +#define memdbg_alloc(X) \ + _memdbg_alloc ((void *)X, log_srcname (__FILE__), __func__, __LINE__); +int memdbg_free (void *ptr); + void memdbg_dump(void); #ifdef __cplusplus diff --git a/src/mimedataprovider.cpp b/src/mimedataprovider.cpp index e073b4b..52c7834 100644 --- a/src/mimedataprovider.cpp +++ b/src/mimedataprovider.cpp @@ -195,7 +195,7 @@ t2body (MimeDataProvider *provider, rfc822parse_t msg) ctx->is_base64_encoded = 1; b64_init (&ctx->base64); } - free (p); + xfree (p); } /* Get the filename from the header. */ diff --git a/src/parsecontroller.cpp b/src/parsecontroller.cpp index 9dfcc23..20753b0 100644 --- a/src/parsecontroller.cpp +++ b/src/parsecontroller.cpp @@ -226,6 +226,7 @@ format_error(GpgME::DecryptionResult result, Protocol protocol) SRCNAME, __func__); return "Failed to Format error."; } + memdbg_alloc (buf); msg = buf; return msg; } @@ -304,6 +305,7 @@ ParseController::parse() /* Should never happen */ m_error = std::string("Bad installation"); } + memdbg_alloc (buf); m_error = buf; xfree (buf); return; diff --git a/src/pgpmime.c b/src/pgpmime.c index 7e48f5f..f0dedfd 100644 --- a/src/pgpmime.c +++ b/src/pgpmime.c @@ -296,7 +296,7 @@ message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg) ctx->is_base64_encoded = 1; b64_init (&ctx->base64); } - free (p); + xfree (p); } /* If this is a text part, decide whether we treat it as our body. */ diff --git a/src/revert.cpp b/src/revert.cpp index 1d3834d..bd0b647 100644 --- a/src/revert.cpp +++ b/src/revert.cpp @@ -160,6 +160,7 @@ gpgol_mailitem_revert (LPDISPATCH mailitem) goto done; } + memdbg_alloc (item_str); attachment = get_oom_object (attachments, item_str); xfree (item_str); if (!attachment) diff --git a/src/rfc2047parse.c b/src/rfc2047parse.c index 10fd7fc..b49af1a 100644 --- a/src/rfc2047parse.c +++ b/src/rfc2047parse.c @@ -122,7 +122,7 @@ rfc2047_token_new_encoded_word (const char *word, size_t len) /* copy the charset into a buffer */ n = (size_t) (inptr - tmpchar); - buf = malloc (n + 1); + buf = xmalloc (n + 1); memcpy (buf, tmpchar, n); buf[n] = '\0'; charset = buf; diff --git a/src/rfc822parse.c b/src/rfc822parse.c index 6df803b..7c5d5ba 100644 --- a/src/rfc822parse.c +++ b/src/rfc822parse.c @@ -39,6 +39,7 @@ #include #include +#include "common_indep.h" #include "rfc822parse.h" enum token_type @@ -184,7 +185,7 @@ new_part (void) { part_t part; - part = calloc (1, sizeof *part); + part = xcalloc (1, sizeof *part); if (part) { part->hdr_lines_tail = &part->hdr_lines; @@ -207,10 +208,10 @@ release_part (part_t part) for (hdr = part->hdr_lines; hdr; hdr = hdr2) { hdr2 = hdr->next; - free (hdr); + xfree (hdr); } - free (part->boundary); - free (part); + xfree (part->boundary); + xfree (part); } } @@ -231,13 +232,13 @@ release_handle_data (rfc822parse_t msg) rfc822parse_t rfc822parse_open (rfc822parse_cb_t cb, void *cb_value) { - rfc822parse_t msg = calloc (1, sizeof *msg); + rfc822parse_t msg = xcalloc (1, sizeof *msg); if (msg) { msg->parts = msg->current_part = new_part (); if (!msg->parts) { - free (msg); + xfree (msg); msg = NULL; } else @@ -247,7 +248,7 @@ rfc822parse_open (rfc822parse_cb_t cb, void *cb_value) if (do_callback (msg, RFC822PARSE_OPEN)) { release_handle_data (msg); - free (msg); + xfree (msg); errno = 0;/* Not meaningful after the callback. */ msg = NULL; } @@ -264,7 +265,7 @@ rfc822parse_cancel (rfc822parse_t msg) { do_callback (msg, RFC822PARSE_CANCEL); release_handle_data (msg); - free (msg); + xfree (msg); } } @@ -276,7 +277,7 @@ rfc822parse_close (rfc822parse_t msg) { do_callback (msg, RFC822PARSE_CLOSE); release_handle_data (msg); - free (msg); + xfree (msg); } } @@ -354,7 +355,7 @@ transition_to_body (rfc822parse_t msg) if (s) { assert (!msg->current_part->boundary); - msg->current_part->boundary = malloc (strlen (s) + 1); + msg->current_part->boundary = xmalloc (strlen (s) + 1); if (msg->current_part->boundary) { part_t part; @@ -420,7 +421,7 @@ insert_header (rfc822parse_t msg, const unsigned char *line, size_t length) do_callback (msg, RFC822PARSE_BEGIN_HEADER); length = length_sans_trailing_ws (line, length); - hdr = malloc (sizeof (*hdr) + length); + hdr = xmalloc (sizeof (*hdr) + length); if (!hdr) return -1; hdr->next = NULL; @@ -543,7 +544,7 @@ rfc822parse_get_field (rfc822parse_t msg, const char *name, int which, for (h2 = h->next; h2 && h2->cont; h2 = h2->next) n += strlen (h2->line) + 1; - buf = p = malloc (n); + buf = p = xmalloc (n); if (buf) { p = my_stpcpy (p, h->line); @@ -694,7 +695,7 @@ release_token_list (TOKEN t) TOKEN t2 = t->next; /* fixme: If we have owner_pantry, put the token back to * this pantry so that it can be reused later */ - free (t); + xfree (t); t = t2; } } @@ -707,7 +708,7 @@ new_token (enum token_type type, const char *buf, size_t length) /* fixme: look through our pantries to find a suitable * token for reuse */ - t = malloc (sizeof *t + length); + t = xmalloc (sizeof *t + length); if (t) { t->next = NULL; @@ -731,7 +732,7 @@ append_to_token (TOKEN old, const char *buf, size_t length) size_t n = strlen (old->data); TOKEN t; - t = malloc (sizeof *t + n + length); + t = xmalloc (sizeof *t + n + length); if (t) { t->next = old->next; diff --git a/src/vasprintf.c b/src/vasprintf.c index 62ee0ad..99149e8 100644 --- a/src/vasprintf.c +++ b/src/vasprintf.c @@ -128,7 +128,7 @@ int_vasprintf (result, format, args) #ifdef TEST global_total_width = total_width; #endif - *result = malloc (total_width); + *result = xmalloc (total_width); if (*result != NULL) return vsprintf (*result, format, *args); else diff --git a/src/w32-gettext.cpp b/src/w32-gettext.cpp index 430eafa..9d9a515 100644 --- a/src/w32-gettext.cpp +++ b/src/w32-gettext.cpp @@ -33,6 +33,7 @@ #include #include "w32-gettext.h" +#include "common_indep.h" #include "xmalloc.h" @@ -1293,14 +1294,14 @@ static void free_domain (struct loaded_domain *domain) { struct overflow_space_s *os, *os2; - free (domain->data); - free (domain->mapped); + xfree (domain->data); + xfree (domain->mapped); for (os = domain->overflow_space; os; os = os2) { os2 = os->next; - free (os); + xfree (os); } - free (domain); + xfree (domain); } @@ -1329,7 +1330,7 @@ load_domain (const char *filename) return NULL; } - data = (mo_file_header*) malloc (size); + data = (mo_file_header*) xmalloc (size); if (!data) { fclose (fp); @@ -1344,7 +1345,7 @@ load_domain (const char *filename) if (nb < to_read) { fclose (fp); - free (data); + xfree (data); return NULL; } read_ptr += nb; @@ -1358,14 +1359,14 @@ load_domain (const char *filename) if (data->magic != MAGIC && data->magic != MAGIC_SWAPPED) { /* The magic number is wrong: not a message catalog file. */ - free (data); + xfree (data); return NULL; } - domain = (loaded_domain *) calloc (1, sizeof *domain); + domain = (loaded_domain *) xcalloc (1, sizeof *domain); if (!domain) { - free (data); + xfree (data); return NULL; } domain->data = (char *) data; @@ -1388,17 +1389,17 @@ load_domain (const char *filename) default: /* This is an invalid revision. */ - free (data); - free (domain); + xfree (data); + xfree (domain); return NULL; } /* Allocate an array to keep track of code page mappings. */ - domain->mapped = (char *) calloc (1, domain->nstrings); + domain->mapped = (char *) xcalloc (1, domain->nstrings); if (!domain->mapped) { - free (data); - free (domain); + xfree (data); + xfree (domain); return NULL; } @@ -1421,14 +1422,14 @@ wchar_to_native (const wchar_t *string) if (n < 0) return NULL; - result = (char*) malloc (n+1); + result = (char*) xmalloc (n+1); if (!result) return NULL; n = WideCharToMultiByte (CP_ACP, 0, string, -1, result, n, NULL, NULL); if (n < 0) { - free (result); + xfree (result); return NULL; } return result; @@ -1445,14 +1446,14 @@ native_to_wchar (const char *string) if (n < 0) return NULL; - result = (wchar_t *) malloc ((n+1) * sizeof *result); + result = (wchar_t *) xmalloc ((n+1) * sizeof *result); if (!result) return NULL; n = MultiByteToWideChar (CP_ACP, 0, string, -1, result, n); if (n < 0) { - free (result); + xfree (result); return NULL; } return result; @@ -1474,14 +1475,14 @@ utf8_to_wchar (const char *string) if (n < 0) return NULL; - result = (wchar_t *) malloc ((n+1) * sizeof *result); + result = (wchar_t *) xmalloc ((n+1) * sizeof *result); if (!result) return NULL; n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n); if (n < 0) { - free (result); + xfree (result); return NULL; } return result; @@ -1549,7 +1550,7 @@ utf8_to_native (const char *string) return xstrdup ("[Error: utf8_to_wchar failed]"); result = wchar_to_native (wstring); - free (wstring); + xfree (wstring); if (!result) result = xstrdup ("[Error: wchar_to_native failed]"); @@ -1572,7 +1573,7 @@ native_to_utf8 (const char *string) return xstrdup ("[Error: native_to_wchar failed]"); result = wchar_to_utf8 (wstring); - free (wstring); + xfree (wstring); if (!result) result = xstrdup ("[Error: wchar_to_utf8 failed]"); @@ -1606,7 +1607,7 @@ get_string (struct loaded_domain *domain, u32 idx, int utf8) in the overflow_space else and mark that in the mapped array. Because we expect that this won't happen too often, we use a simple linked list. */ - os = (overflow_space_s *) malloc (sizeof *os + buflen); + os = (overflow_space_s *) xmalloc (sizeof *os + buflen); if (os) { os->idx = idx; @@ -1618,7 +1619,7 @@ get_string (struct loaded_domain *domain, u32 idx, int utf8) else p = (char *) "ERROR in GETTEXT MALLOC"; } - free (buf); + xfree (buf); } else if (domain->mapped[idx] == 2) { @@ -1684,10 +1685,10 @@ bindtextdomain (const char *domainname, const char *dirname) + strlen (domainname) + 3 + 1; char *p; - fname = (char*) malloc (len); + fname = (char*) xmalloc (len); if (!fname) { - free (catval); + xfree (catval); return NULL; } @@ -1705,8 +1706,8 @@ bindtextdomain (const char *domainname, const char *dirname) } domain = load_domain (fname); - free (catval); - free (fname); + xfree (catval); + xfree (fname); /* We should not be invoked twice, but this is how you would do it if it happened. */ diff --git a/src/windowmessages.cpp b/src/windowmessages.cpp index 4302e12..84c66b5 100644 --- a/src/windowmessages.cpp +++ b/src/windowmessages.cpp @@ -315,7 +315,7 @@ do_async (LPVOID arg) void do_in_ui_thread_async (gpgol_wmsg_type type, void *data, int delay) { - wm_ctx_t *ctx = (wm_ctx_t *) calloc (1, sizeof (wm_ctx_t)); + wm_ctx_t *ctx = (wm_ctx_t *) xcalloc (1, sizeof (wm_ctx_t)); ctx->wmsg_type = type; ctx->data = data; ctx->delay = delay; diff --git a/src/wks-helper.cpp b/src/wks-helper.cpp index 817c487..8ddbf35 100644 --- a/src/wks-helper.cpp +++ b/src/wks-helper.cpp @@ -413,6 +413,7 @@ WKSHelper::notify (const char *cBox) const "it easy for others to send you encrypted mail.\n\n" "It's secure and free!\n\n" "Register automatically?"), mbox.c_str ()); + memdbg_alloc (buf); if (gpgol_message_box (get_active_hwnd (), buf, _("GpgOL: Pubkey directory available!"), MB_YESNO) == IDYES) diff --git a/src/xmalloc.h b/src/xmalloc.h index d29eb31..5385419 100644 --- a/src/xmalloc.h +++ b/src/xmalloc.h @@ -28,13 +28,62 @@ extern "C" { #endif /*-- common.c --*/ -void* xmalloc (size_t n); -void* xcalloc (size_t m, size_t n); -void *xrealloc (void *a, size_t n); -char* xstrdup (const char *s); -void xfree (void *p); -void out_of_core (void); +#define xmalloc(VAR1) ({void *retval; \ + retval = _xmalloc(VAR1); \ + if ((opt.enable_debug & DBG_OOM_EXTRA)) \ + { \ + memdbg_alloc (retval); \ + } \ +retval;}) + +#define xcalloc(VAR1, VAR2) ({void *retval; \ + retval = _xcalloc(VAR1, VAR2); \ + if ((opt.enable_debug & DBG_OOM_EXTRA)) \ + { \ + memdbg_alloc (retval);\ + } \ +retval;}) + +#define xrealloc(VAR1, VAR2) ({void *retval; \ + retval = _xrealloc (VAR1, VAR2); \ + if ((opt.enable_debug & DBG_OOM_EXTRA)) \ + { \ + memdbg_alloc (retval);\ + memdbg_free ((void*)VAR1); \ + } \ +retval;}) + +#define xfree(VAR1) \ +{ \ + if (VAR1 && (opt.enable_debug & DBG_OOM_EXTRA) && !memdbg_free (VAR1)) \ + log_debug ("%s:%s:%i %p freed here", \ + log_srcname (__FILE__), __func__, __LINE__, VAR1); \ + _xfree (VAR1); \ +} + +#define xstrdup(VAR1) ({char *retval; \ + retval = _xstrdup (VAR1); \ + if ((opt.enable_debug & DBG_OOM_EXTRA)) \ + { \ + memdbg_alloc ((void *)retval);\ + } \ +retval;}) +#define xwcsdup(VAR1) ({wchar_t *retval; \ + retval = _xwcsdup (VAR1); \ + if ((opt.enable_debug & DBG_OOM_EXTRA)) \ + { \ + memdbg_alloc ((void *)retval);\ + } \ +retval;}) + +void* _xmalloc (size_t n); +void* _xcalloc (size_t m, size_t n); +void *_xrealloc (void *a, size_t n); +char* _xstrdup (const char *s); +wchar_t * _xwcsdup (const wchar_t *s); +void _xfree (void *p); +void out_of_core (void); #ifdef __cplusplus } commit bf3ed229470a0c4691e3cb06855ba24caaa99008 Author: Andre Heinecke Date: Mon Jul 23 13:54:27 2018 +0200 Fix tmp path naming if name exists * src/common.cpp (get_tmp_outfile): Fix name. diff --git a/src/common.cpp b/src/common.cpp index 9c0d6e2..0f585eb 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -489,11 +489,11 @@ get_tmp_outfile (wchar_t *name, HANDLE *outHandle) // OutNameC is now without an extension and if // there is a file ext it now points to the extension. - outName = tmpPath + outNameC + std::to_string(tries++); + outName = outNameC + std::string("_") + std::to_string(tries++); if (fileExt) { - outName += fileExt; + outName += std::string(".") + fileExt; } xfree (outNameC); commit 2a4f79650b1e1876f71ec9c7a5d9dfa95a3a293c Author: Andre Heinecke Date: Mon Jul 23 13:04:34 2018 +0200 strdup -> xstrdup -- diff --git a/src/common.cpp b/src/common.cpp index 689a0b9..9c0d6e2 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -198,7 +198,7 @@ read_w32_registry_string (const char *root, const char *dir, const char *name) { return nullptr; } - return strdup (ret.c_str ()); + return xstrdup (ret.c_str ()); } /* Return the data dir used for forms etc. Returns NULL on error. */ @@ -468,7 +468,7 @@ get_tmp_outfile (wchar_t *name, HANDLE *outHandle) log_debug_w32 (-1, "%s:%s: Failed to open candidate '%s'", SRCNAME, __func__, outName.c_str()); - char *outNameC = strdup (outName.c_str()); + char *outNameC = xstrdup (outName.c_str()); const auto lastBackslash = strrchr (outNameC, '\\'); if (!lastBackslash) diff --git a/src/cpphelp.cpp b/src/cpphelp.cpp index 2dc25a4..5912f81 100644 --- a/src/cpphelp.cpp +++ b/src/cpphelp.cpp @@ -76,7 +76,7 @@ vector_to_cArray(const std::vector &vec) char ** ret = (char**) xmalloc (sizeof (char*) * (vec.size() + 1)); for (size_t i = 0; i < vec.size(); i++) { - ret[i] = strdup (vec[i].c_str()); + ret[i] = xstrdup (vec[i].c_str()); } ret[vec.size()] = NULL; return ret; diff --git a/src/mapihelp.cpp b/src/mapihelp.cpp index afe6d7f..301f692 100644 --- a/src/mapihelp.cpp +++ b/src/mapihelp.cpp @@ -326,7 +326,7 @@ mapi_get_uid (LPMESSAGE msg) } else if (PROP_TYPE (propval->ulPropTag) == PT_STRING8) { - ret = strdup (propval->Value.lpszA); + ret = xstrdup (propval->Value.lpszA); log_debug ("%s:%s: Fund uuid in MAPI for %p", SRCNAME, __func__, msg); } diff --git a/src/memdbg.cpp b/src/memdbg.cpp index 0a50513..aabf2a8 100644 --- a/src/memdbg.cpp +++ b/src/memdbg.cpp @@ -53,7 +53,7 @@ register_name (void *obj, const char *nameSuggestion) if (!name && nameSuggestion) { - name = strdup (nameSuggestion); + name = xstrdup (nameSuggestion); suggestionUsed = true; } if (!name) diff --git a/src/mimemaker.cpp b/src/mimemaker.cpp index 4dd55a9..216acdf 100644 --- a/src/mimemaker.cpp +++ b/src/mimemaker.cpp @@ -176,7 +176,7 @@ create_mapi_attachment (LPMESSAGE message, sink_t sink, /* We better insert a short filename. */ prop.ulPropTag = PR_ATTACH_FILENAME_A; - prop.Value.lpszA = strdup (MIMEATTACHFILENAME); + prop.Value.lpszA = xstrdup (MIMEATTACHFILENAME); hr = HrSetOneProp ((LPMAPIPROP)att, &prop); xfree (prop.Value.lpszA); if (hr) @@ -197,8 +197,8 @@ create_mapi_attachment (LPMESSAGE message, sink_t sink, if (!hr) { prop.ulPropTag = PR_ATTACH_MIME_TAG_A; - prop.Value.lpszA = overrideMimeTag ? strdup (overrideMimeTag) : - strdup ("multipart/signed"); + prop.Value.lpszA = overrideMimeTag ? xstrdup (overrideMimeTag) : + xstrdup ("multipart/signed"); if (overrideMimeTag) { log_debug ("%s:%s: using override mimetag: %s\n", @@ -1150,11 +1150,11 @@ finalize_message (LPMESSAGE message, mapi_attach_item_t *att_table, prop.ulPropTag = PR_MESSAGE_CLASS_A; if (encrypt) { - prop.Value.lpszA = strdup ("IPM.Note.InfoPathForm.GpgOL.SMIME.MultipartSigned"); + prop.Value.lpszA = xstrdup ("IPM.Note.InfoPathForm.GpgOL.SMIME.MultipartSigned"); } else { - prop.Value.lpszA = strdup ("IPM.Note.InfoPathForm.GpgOLS.SMIME.MultipartSigned"); + prop.Value.lpszA = xstrdup ("IPM.Note.InfoPathForm.GpgOLS.SMIME.MultipartSigned"); } if (!is_inline) diff --git a/src/mlang-charset.cpp b/src/mlang-charset.cpp index eb4cc85..e9b327a 100644 --- a/src/mlang-charset.cpp +++ b/src/mlang-charset.cpp @@ -48,7 +48,7 @@ char *ansi_charset_to_utf8 (const char *charset, const char *input, { log_debug ("%s:%s: No charset / codepage returning plain.", SRCNAME, __func__); - return strdup (input); + return xstrdup (input); } CoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, @@ -84,7 +84,7 @@ char *ansi_charset_to_utf8 (const char *charset, const char *input, log_error ("%s:%s: Failed to find charset for: %s", SRCNAME, __func__, charset); gpgol_release (multilang); - return strdup(input); + return xstrdup (input); } enc = (mime_info.uiInternetEncoding == 0) ? mime_info.uiCodePage : mime_info.uiInternetEncoding; diff --git a/src/oomhelp.cpp b/src/oomhelp.cpp index 1a11560..297fe0b 100644 --- a/src/oomhelp.cpp +++ b/src/oomhelp.cpp @@ -1918,7 +1918,7 @@ generate_uid () unsigned char *str; UuidToStringA (&uuid, &str); - char *ret = strdup ((char*)str); + char *ret = xstrdup ((char*)str); RpcStringFreeA (&str); return ret; @@ -1956,7 +1956,7 @@ get_unique_id (LPDISPATCH mail, int create, const char *uuid) } else { - newuid = strdup (uuid); + newuid = xstrdup (uuid); } int ret = put_pa_string (mail, GPGOL_UID_DASL, newuid); diff --git a/src/rfc2047parse.c b/src/rfc2047parse.c index 56e5dba..10fd7fc 100644 --- a/src/rfc2047parse.c +++ b/src/rfc2047parse.c @@ -652,7 +652,7 @@ rfc2047_parse (const char *input) { char *decoded; if (!input) - return strdup (""); + return xstrdup (""); log_debug ("%s:%s: Input: \"%s\"", SRCNAME, __func__, input); @@ -665,7 +665,7 @@ rfc2047_parse (const char *input) if (!decoded || !strlen (decoded)) { xfree (decoded); - return strdup (input); + return xstrdup (input); } return decoded; } diff --git a/src/w32-gettext.cpp b/src/w32-gettext.cpp index b89bc79..430eafa 100644 --- a/src/w32-gettext.cpp +++ b/src/w32-gettext.cpp @@ -1596,7 +1596,7 @@ get_string (struct loaded_domain *domain, u32 idx, int utf8) domain->mapped[idx] = 1; plen = strlen (p); - buf = utf8 ? strdup (p) : utf8_to_native (p); + buf = utf8 ? xstrdup (p) : utf8_to_native (p); buflen = strlen (buf); if (buflen <= plen) strcpy (p, buf); diff --git a/src/wks-helper.cpp b/src/wks-helper.cpp index 109ecab..817c487 100644 --- a/src/wks-helper.cpp +++ b/src/wks-helper.cpp @@ -300,7 +300,7 @@ WKSHelper::start_check (const std::string &mbox, bool forced) const log_debug ("%s:%s: WKSHelper starting check", SRCNAME, __func__); /* Start the actual work that can be done in a background thread. */ - CloseHandle (CreateThread (nullptr, 0, do_check, strdup (mbox.c_str ()), 0, + CloseHandle (CreateThread (nullptr, 0, do_check, xstrdup (mbox.c_str ()), 0, nullptr)); return; } @@ -386,7 +386,7 @@ WKSHelper::allow_notify (int sleepTimeMS) const if (pair.second == ConfirmationSeen || pair.second == NeedsPublish) { - auto *args = new std::pair (strdup (pair.first.c_str()), + auto *args = new std::pair (xstrdup (pair.first.c_str()), sleepTimeMS); CloseHandle (CreateThread (nullptr, 0, do_notify, args, 0, commit f4c21ec09d8451294a3137532bde7ae77993e34c Author: Andre Heinecke Date: Mon Jul 23 09:42:59 2018 +0200 Remove unused code * src/main.c (create_initialization_vector) (get_crypt_random): Removed. diff --git a/src/main.c b/src/main.c index 9d723bd..5b6cdb7 100644 --- a/src/main.c +++ b/src/main.c @@ -59,29 +59,6 @@ initialize_main (void) return log_mutex? 0 : -1; } -/* Return nbytes of cryptographic strong random. Caller needs to free - the returned buffer. */ -static char * -get_crypt_random (size_t nbytes) -{ - HCRYPTPROV prov; - char *buffer; - - if (!CryptAcquireContext (&prov, NULL, NULL, PROV_RSA_FULL, - (CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) ) - return NULL; - - buffer = xmalloc (nbytes); - if (!CryptGenRandom (prov, nbytes, buffer)) - { - xfree (buffer); - buffer = NULL; - } - CryptReleaseContext (prov, 0); - return buffer; -} - - void i18n_init (void) { @@ -167,14 +144,6 @@ DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved) return TRUE; } -/* Return a new allocated IV of size NBYTES. Caller must free it. On - error NULL is returned. */ -void * -create_initialization_vector (size_t nbytes) -{ - return get_crypt_random (nbytes); -} - static char * get_locale_dir (void) { commit c1085f44e1771bacf5fca24faca9c45cc6f7bd35 Author: Andre Heinecke Date: Mon Jul 23 09:31:51 2018 +0200 Make async encryption optional * src/common_indep.h (opt): Add sync_enc. * src/mail.cpp (Mail::isAsynCryptDisabled_o): Respect it. * src/main.c (read_options): Read it. -- If we have users where GpgOL crashes on send we or the user might want to disable async encryption. GnuPG-Bug-Id: T3838 diff --git a/src/common_indep.h b/src/common_indep.h index 0997594..7175cf9 100644 --- a/src/common_indep.h +++ b/src/common_indep.h @@ -197,6 +197,7 @@ struct int reply_crypt; /* Only for Addin. Encrypt / Sign based on cryptostatus. */ int automation; /* General automation */ int autotrust; /* TOFU configured for GpgOL */ + int sync_enc; /* Disabed async encryption */ int prefer_smime; /* S/MIME prefered when autoresolving */ int smime_html_warn_shown; /* Flag to save if unsigned smime warning was shown */ diff --git a/src/mail.cpp b/src/mail.cpp index ad76238..0836bba 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -71,8 +71,6 @@ static Mail *s_last_mail; #define COPYBUFSIZE (8 * 1024) -#define DO_ASYNC_CRYPTO - Mail::Mail (LPDISPATCH mailitem) : m_mailitem(mailitem), m_processed(false), @@ -3018,7 +3016,13 @@ Mail::check_inline_response () /* Async sending might lead to crashes when the send invocation is done. * For now we treat every mail as an inline response to disable async * encryption. :-( For more details see: T3838 */ -#ifdef DO_ASYNC_CRYPTO + + if (opt.sync_enc) + { + m_async_crypt_disabled = true; + return m_async_crypt_disabled; + } + m_async_crypt_disabled = false; LPDISPATCH app = GpgolAddin::get_instance ()->get_application (); if (!app) @@ -3058,9 +3062,6 @@ Mail::check_inline_response () m_async_crypt_disabled = true; } xfree (inlineSubject); -#else - m_async_crypt_disabled = true; -#endif return m_async_crypt_disabled; } diff --git a/src/main.c b/src/main.c index 12754fb..9d723bd 100644 --- a/src/main.c +++ b/src/main.c @@ -309,6 +309,7 @@ read_options (void) opt.automation = get_conf_bool ("automation", 1); opt.autosecure = get_conf_bool ("autosecure", 1); opt.autotrust = get_conf_bool ("autotrust", 0); + opt.sync_enc = get_conf_bool ("syncEnc", 0); opt.smime_html_warn_shown = get_conf_bool ("smimeHtmlWarnShown", 0); if (!opt.automation) commit efaddd81771b267b155595df4f43d3e1b72cd100 Author: Andre Heinecke Date: Mon Jul 23 08:15:30 2018 +0200 Improve invalidation blocking * src/mail.cpp (do_parsing): Don't use invalidation_lock. We now have block invalidation. * src/mailitem-events.cpp (Read): Delay invalidate. * src/windowmessages.cpp (delayed_invalidate_ui): Take sleep param. (INVALIDATE_UI): Respect invalidation blocked. * src/windowmessages.h: Update accordingly. -- This works much better then the try to archive minimizing invalidations by using a lock. diff --git a/src/mail.cpp b/src/mail.cpp index ba134d2..ad76238 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -741,7 +741,6 @@ do_parsing (LPVOID arg) gpgrt_lock_unlock (&dtor_lock); gpgrt_lock_lock (&parser_lock); - gpgrt_lock_lock (&invalidate_lock); /* We lock the parser here to avoid too many decryption attempts if there are multiple mailobjects which might have already @@ -755,7 +754,6 @@ do_parsing (LPVOID arg) { log_debug ("%s:%s: cancel for: %p already deleted", SRCNAME, __func__, arg); - gpgrt_lock_unlock (&invalidate_lock); gpgrt_lock_unlock (&parser_lock); unblockInv(); return 0; @@ -765,14 +763,12 @@ do_parsing (LPVOID arg) { log_error ("%s:%s: no parser found for mail: %p", SRCNAME, __func__, arg); - gpgrt_lock_unlock (&invalidate_lock); gpgrt_lock_unlock (&parser_lock); unblockInv(); return -1; } parser->parse(); do_in_ui_thread (PARSING_DONE, arg); - gpgrt_lock_unlock (&invalidate_lock); gpgrt_lock_unlock (&parser_lock); unblockInv(); return 0; @@ -1410,7 +1406,7 @@ Mail::parsing_done() log_debug ("%s:%s: Delayed invalidate to update sigstate.", SRCNAME, __func__); - CloseHandle(CreateThread (NULL, 0, delayed_invalidate_ui, (LPVOID) this, 0, + CloseHandle(CreateThread (NULL, 0, delayed_invalidate_ui, (LPVOID) 300, 0, NULL)); TRACEPOINT; return; diff --git a/src/mailitem-events.cpp b/src/mailitem-events.cpp index 0769df1..09a9fea 100644 --- a/src/mailitem-events.cpp +++ b/src/mailitem-events.cpp @@ -188,7 +188,7 @@ EVENT_SINK_INVOKE(MailItemEvents) log_debug ("%s:%s: Non crypto mail %p opened. Updating sigstatus.", SRCNAME, __func__, m_mail); /* Ensure that no wrong sigstatus is shown */ - CloseHandle(CreateThread (NULL, 0, delayed_invalidate_ui, (LPVOID) this, 0, + CloseHandle(CreateThread (NULL, 0, delayed_invalidate_ui, (LPVOID) 300, 0, NULL)); break; } diff --git a/src/windowmessages.cpp b/src/windowmessages.cpp index 9b5c46b..4302e12 100644 --- a/src/windowmessages.cpp +++ b/src/windowmessages.cpp @@ -33,6 +33,7 @@ /* Singleton window */ static HWND g_responder_window = NULL; +static int invalidation_blocked = 0; LONG_PTR WINAPI gpgol_window_proc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) @@ -98,11 +99,20 @@ gpgol_window_proc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } case (INVALIDATE_UI): { - log_debug ("%s:%s: Invalidating UI", - SRCNAME, __func__); - gpgoladdin_invalidate_ui(); - log_debug ("%s:%s: Invalidation done", - SRCNAME, __func__); + if (!invalidation_blocked) + { + log_debug ("%s:%s: Invalidating UI", + SRCNAME, __func__); + gpgoladdin_invalidate_ui(); + log_debug ("%s:%s: Invalidation done", + SRCNAME, __func__); + } + else + { + log_debug ("%s:%s: Received invalidation msg while blocked." + " Ignoring it", + SRCNAME, __func__); + } break; } case (INVALIDATE_LAST_MAIL): @@ -421,14 +431,12 @@ create_message_hook() GetCurrentThreadId()); } -gpgrt_lock_t invalidate_lock = GPGRT_LOCK_INITIALIZER; +GPGRT_LOCK_DEFINE (invalidate_lock); static bool invalidation_in_progress; -static int invalidation_blocked = 0; - DWORD WINAPI -delayed_invalidate_ui (LPVOID) +delayed_invalidate_ui (LPVOID minsleep) { if (invalidation_in_progress) { @@ -440,6 +448,7 @@ delayed_invalidate_ui (LPVOID) invalidation_in_progress = true; gpgrt_lock_lock(&invalidate_lock); + Sleep((int) minsleep); int i = 0; while (invalidation_blocked) { diff --git a/src/windowmessages.h b/src/windowmessages.h index 29364a0..175bb52 100644 --- a/src/windowmessages.h +++ b/src/windowmessages.h @@ -102,12 +102,9 @@ void blockInv (); void unblockInv (); DWORD WINAPI -delayed_invalidate_ui (LPVOID); +delayed_invalidate_ui (LPVOID minsleep_ms = 0); DWORD WINAPI close_mail (LPVOID); -/* The lock to invalide the ui */ -extern gpgrt_lock_t invalidate_lock; - #endif // WINDOWMESSAGES_H commit b881eebb0d89e7ce000b01a96c35d137ba558509 Author: Andre Heinecke Date: Mon Jul 23 08:12:16 2018 +0200 Trace return of UI callbacks * src/ribbon-callbacks.cpp: Trace returns. -- These functions are often times the last functions in the log of a crash as they are called whenever the UI changed. There is no crash in them but to better see it anway we log when they are done. diff --git a/src/ribbon-callbacks.cpp b/src/ribbon-callbacks.cpp index 9ba0796..42a020e 100644 --- a/src/ribbon-callbacks.cpp +++ b/src/ribbon-callbacks.cpp @@ -537,6 +537,7 @@ HRESULT get_is_details_enabled (LPDISPATCH ctrl, VARIANT *result) result->pboolVal = (VARIANT_BOOL*) xmalloc (sizeof (VARIANT_BOOL)); *(result->pboolVal) = none_selected ? VARIANT_FALSE : VARIANT_TRUE; + TRACEPOINT; return S_OK; } @@ -558,6 +559,7 @@ HRESULT get_sig_label (LPDISPATCH ctrl, VARIANT *result) w_result = utf8_to_wchar (mail->getCryptoSummary ().c_str ()); result->bstrVal = SysAllocString (w_result); xfree (w_result); + TRACEPOINT; return S_OK; } @@ -581,6 +583,7 @@ HRESULT get_sig_ttip (LPDISPATCH ctrl, VARIANT *result) } result->bstrVal = SysAllocString (w_result); xfree (w_result); + TRACEPOINT; return S_OK; } @@ -592,6 +595,7 @@ HRESULT get_sig_stip (LPDISPATCH ctrl, VARIANT *result) if (none_selected) { result->bstrVal = SysAllocString (L""); + TRACEPOINT; return S_OK; } if (!mail || !mail->isCryptoMail ()) @@ -602,12 +606,14 @@ HRESULT get_sig_stip (LPDISPATCH ctrl, VARIANT *result) "Click here to learn more.")); result->bstrVal = SysAllocString (w_result); xfree (w_result); + TRACEPOINT; return S_OK; } const auto message = mail->getCryptoDetails_o (); wchar_t *w_message = utf8_to_wchar (message.c_str()); result->bstrVal = SysAllocString (w_message); xfree (w_message); + TRACEPOINT; return S_OK; } @@ -712,8 +718,10 @@ HRESULT get_crypto_icon (LPDISPATCH ctrl, VARIANT *result) if (mail) { + TRACEPOINT; return getIcon (mail->getCryptoIconID (), result); } + TRACEPOINT; return getIcon (IDI_LEVEL_0, result); } @@ -726,6 +734,7 @@ HRESULT get_is_crypto_mail (LPDISPATCH ctrl, VARIANT *result) *(result->pboolVal) = (mail && (mail->isSigned () || mail->isEncrypted ())) ? VARIANT_TRUE : VARIANT_FALSE; + TRACEPOINT; return S_OK; } commit 1020ddceb349e508cadcae8155708bd3d5937aa9 Author: Andre Heinecke Date: Mon Jul 23 08:09:26 2018 +0200 Fix invalidate UI only on unselect * src/explorer-events.cpp (start_watchdog): Only invalidate UI on unselect. diff --git a/src/explorer-events.cpp b/src/explorer-events.cpp index d4087d1..e9dd776 100644 --- a/src/explorer-events.cpp +++ b/src/explorer-events.cpp @@ -148,10 +148,12 @@ start_watchdog (LPVOID arg) log_debug ("%s:%s: Deteced unselect invalidating UI.", SRCNAME, __func__); it->second = UnselectSeen; + gpgrt_lock_unlock (&explorer_map_lock); + do_in_ui_thread (INVALIDATE_UI, nullptr); + return 0; } gpgrt_lock_unlock (&explorer_map_lock); - do_in_ui_thread (INVALIDATE_UI, nullptr); return 0; } commit dff52c1a96c4b28ee2c5f66493d19507dacda5ca Author: Andre Heinecke Date: Mon Jul 23 08:08:06 2018 +0200 unique_ptr++ * src/parsecontroller.cpp (ParseController::get_ultimate_keys): Use unique ptr for context. diff --git a/src/parsecontroller.cpp b/src/parsecontroller.cpp index 1b19aba..9dfcc23 100644 --- a/src/parsecontroller.cpp +++ b/src/parsecontroller.cpp @@ -576,7 +576,7 @@ ParseController::get_ultimate_keys() } log_debug ("%s:%s: Starting keylisting.", SRCNAME, __func__); - auto ctx = Context::createForProtocol (OpenPGP); + auto ctx = std::unique_ptr (Context::createForProtocol (OpenPGP)); if (!ctx) { /* Maybe PGP broken and not S/MIME */ @@ -592,7 +592,6 @@ ParseController::get_ultimate_keys() { log_error ("%s:%s: Failed to start keylisting err: %i: %s", SRCNAME, __func__, err.code (), err.asString()); - delete ctx; gpgrt_lock_unlock (&keylist_lock); return s_ultimate_keys; } @@ -626,7 +625,6 @@ ParseController::get_ultimate_keys() } } TRACEPOINT; - delete ctx; log_debug ("%s:%s: keylisting done.", SRCNAME, __func__); commit 9dfe1f112bc5da8d5b2240547c8fcc2751ff895b Author: Andre Heinecke Date: Fri Jul 20 15:52:52 2018 +0200 Fix make dist * po/POTFILES.in: Update file list. diff --git a/po/POTFILES.in b/po/POTFILES.in index 9bb7716..39e66c3 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,7 +1,6 @@ src/addin-options.cpp -src/common.c +src/common.cpp src/common.h -src/config-dialog.c src/eventsink.h src/gpgoladdin.cpp src/gpgoladdin.h commit 945d6a7dd8841c40bfe5986baa4a0d65c26f9c6b Author: Andre Heinecke Date: Fri Jul 20 15:52:09 2018 +0200 Next version will be 2.3.0 * configure.ac: Bump minor version. -- Lots of traumatic changes. diff --git a/configure.ac b/configure.ac index b4f92ee..05de361 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ min_automake_version="1.14" # (git tag -s gpgol-k.n.m) and run "./autogen.sh --force". Please # bump the version number immediately *after* the release and do # another commit and push so that the git magic is able to work. -m4_define([mym4_version], [2.2.1]) +m4_define([mym4_version], [2.3.0]) # Below is m4 magic to extract and compute the git revision number, # the decimalized short revision number, a beta version string and a ----------------------------------------------------------------------- Summary of changes: configure.ac | 2 +- po/POTFILES.in | 3 +-- src/common.cpp | 20 +++++++------- src/common_indep.c | 23 +++++++++++----- src/common_indep.h | 1 + src/cpphelp.cpp | 6 +++-- src/explorer-events.cpp | 4 ++- src/filetype.c | 9 ++++--- src/gpgoladdin.cpp | 1 + src/mail.cpp | 26 ++++++++++-------- src/mailitem-events.cpp | 3 ++- src/main.c | 47 ++++++++------------------------- src/mapihelp.cpp | 4 +-- src/memdbg.cpp | 69 +++++++++++++++++++++++++++++++++++++++++++++++- src/memdbg.h | 5 ++++ src/mimedataprovider.cpp | 2 +- src/mimemaker.cpp | 10 +++---- src/mlang-charset.cpp | 4 +-- src/oomhelp.cpp | 4 +-- src/parsecontroller.cpp | 6 ++--- src/pgpmime.c | 2 +- src/revert.cpp | 1 + src/rfc2047parse.c | 6 ++--- src/rfc822parse.c | 31 +++++++++++----------- src/ribbon-callbacks.cpp | 9 +++++++ src/vasprintf.c | 2 +- src/w32-gettext.cpp | 59 +++++++++++++++++++++-------------------- src/windowmessages.cpp | 29 +++++++++++++------- src/windowmessages.h | 5 +--- src/wks-helper.cpp | 5 ++-- src/xmalloc.h | 61 +++++++++++++++++++++++++++++++++++++----- 31 files changed, 299 insertions(+), 160 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 23 16:11:06 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Mon, 23 Jul 2018 16:11:06 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-115-g43cd178 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via 43cd17881983b02d90062bca8050f07c97fe325f (commit) via 9d83c52581904721c588b50fdd2e15bb7c959d0c (commit) via 39c6972b0cd4cb246a9b00c7cdb065fa9f0f3e81 (commit) via ba00082d4606a7b27e07de41924c05f655cbb727 (commit) via 8865d390bed5cb9605cf3d4a62688a9b1c627b23 (commit) via d740a8afd0c1b65216701f2cc4ac486e867d5b9d (commit) via 2c19657c31369e9791f6aae035331c3e8cf61cd8 (commit) via 0d2d92689189178a14bd4c86bba6960667e1d6e6 (commit) via eb9236394ef217d908df44d9839b18c293ac0564 (commit) from 26d222dfd48c4726d2699a9ec40df5dd6ecafe1f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 43cd17881983b02d90062bca8050f07c97fe325f Author: Andre Heinecke Date: Mon Jul 23 16:09:51 2018 +0200 Fix important memleak in get_mail_from_control * src/ribbon-callbacks.cpp (get_mail_from_control): Fix memleak. -- This function is called 4 times for each invalidate UI so this leak is important even if it just leaks a few bytes. diff --git a/src/ribbon-callbacks.cpp b/src/ribbon-callbacks.cpp index 6c50a40..d2310e0 100644 --- a/src/ribbon-callbacks.cpp +++ b/src/ribbon-callbacks.cpp @@ -357,8 +357,15 @@ get_mail_from_control (LPDISPATCH ctrl, bool *none_selected) hr); return NULL; } + char *name = get_object_name (context); - const auto ctx_name = std::string (get_object_name (context)); + std::string ctx_name; + + if (name) + { + ctx_name = name; + xfree (name); + } if (ctx_name.empty()) { commit 9d83c52581904721c588b50fdd2e15bb7c959d0c Author: Andre Heinecke Date: Mon Jul 23 16:08:52 2018 +0200 Improve wchar and utf8 conversion memdbg * src/w32-gettext.h (wchar_to_utf8, utf8_to_wchar): replace by logging macros. diff --git a/src/ribbon-callbacks.cpp b/src/ribbon-callbacks.cpp index 03d4d98..6c50a40 100644 --- a/src/ribbon-callbacks.cpp +++ b/src/ribbon-callbacks.cpp @@ -288,8 +288,7 @@ HRESULT get_crypt_pressed (LPDISPATCH ctrl, int flags, VARIANT *result, LPMESSAGE message = NULL; result->vt = VT_BOOL | VT_BYREF; - result->pboolVal = (VARIANT_BOOL*) xmalloc (sizeof (VARIANT_BOOL)); - *(result->pboolVal) = VARIANT_FALSE; + result->pboolVal = &var_false; /* First the usual defensive check about our parameters */ if (!ctrl || !result) diff --git a/src/w32-gettext.h b/src/w32-gettext.h index 7374ae9..7232147 100644 --- a/src/w32-gettext.h +++ b/src/w32-gettext.h @@ -64,12 +64,19 @@ static inline const char *gettext_localename (void) { return ""; } #endif /* !ENABLE_NLS */ + +/* Conversion function. */ +char *_wchar_to_utf8 (const wchar_t *string); +wchar_t *_utf8_to_wchar (const char *string); +char *utf8_to_native (const char *string); +char *native_to_utf8 (const char *string); + #define utf8_to_wchar(VAR1) ({wchar_t *retval; \ retval = _utf8_to_wchar (VAR1); \ if ((opt.enable_debug & DBG_OOM_EXTRA)) \ { \ - log_debug ("%s:%s:%i wchar_t alloc %p", \ - SRCNAME, __func__, __LINE__, retval); \ + log_debug ("%s:%s:%i wchar_t alloc %p:%S", \ + SRCNAME, __func__, __LINE__, retval, retval); \ } \ retval;}) @@ -77,18 +84,11 @@ retval;}) retval = _wchar_to_utf8 (VAR1); \ if ((opt.enable_debug & DBG_OOM_EXTRA)) \ { \ - log_debug ("%s:%s:%i char utf8 alloc %p", \ - SRCNAME, __func__, __LINE__, retval); \ + log_debug ("%s:%s:%i char utf8 alloc %p:%s", \ + SRCNAME, __func__, __LINE__, retval, retval); \ } \ retval;}) - -/* Conversion function. */ -char *_wchar_to_utf8 (const wchar_t *string); -wchar_t *_utf8_to_wchar (const char *string); -char *utf8_to_native (const char *string); -char *native_to_utf8 (const char *string); - #ifdef __cplusplus } #include commit 39c6972b0cd4cb246a9b00c7cdb065fa9f0f3e81 Author: Andre Heinecke Date: Mon Jul 23 16:07:57 2018 +0200 Remove dead code * src/mail.cpp, src/mail.h (getHTMLBody_o): Removed. diff --git a/src/mail.cpp b/src/mail.cpp index 1faf8dd..afad308 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -1811,12 +1811,6 @@ Mail::getBody_o () const return get_string_o (m_mailitem, "Body"); } -std::string -Mail::getHTMLBody_o () const -{ - return get_string_o (m_mailitem, "HTMLBody"); -} - std::vector Mail::getRecipients_o () const { diff --git a/src/mail.h b/src/mail.h index ef04c9f..cc4a78b 100644 --- a/src/mail.h +++ b/src/mail.h @@ -391,9 +391,6 @@ public: /** Get the body of the mail */ std::string getBody_o () const; - /** Get the html of the mail */ - std::string getHTMLBody_o () const; - /** Get the recipients. */ std::vector getRecipients_o () const; commit ba00082d4606a7b27e07de41924c05f655cbb727 Author: Andre Heinecke Date: Mon Jul 23 16:07:09 2018 +0200 Minor initialzation * src/mail.cpp (Mail::decryptVerify_o): Initialize placeholder. diff --git a/src/mail.cpp b/src/mail.cpp index a03a7d9..1faf8dd 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -997,7 +997,7 @@ Mail::decryptVerify_o () /* Insert placeholder */ - char *placeholder_buf; + char *placeholder_buf = nullptr; if (m_type == MSGTYPE_GPGOL_WKS_CONFIRMATION) { gpgrt_asprintf (&placeholder_buf, opt.prefer_html ? decrypt_template_html : commit 8865d390bed5cb9605cf3d4a62688a9b1c627b23 Author: Andre Heinecke Date: Mon Jul 23 16:06:35 2018 +0200 Fix super minor memleak * src/gpgoladdin.cpp (GpgolAddin::OnConnection): Release version. diff --git a/src/gpgoladdin.cpp b/src/gpgoladdin.cpp index cf58167..abf8e71 100644 --- a/src/gpgoladdin.cpp +++ b/src/gpgoladdin.cpp @@ -344,6 +344,7 @@ GpgolAddin::OnConnection (LPDISPATCH Application, ext_ConnectMode ConnectMode, return S_OK; } + xfree (version); setupDoNotDisable (); if (ConnectMode != ext_cm_Startup) commit d740a8afd0c1b65216701f2cc4ac486e867d5b9d Author: Andre Heinecke Date: Mon Jul 23 15:34:35 2018 +0200 Fix memleak in put_pa_string * src/oomhelp.cpp (put_pa_string): Fix memleak. -- Its a definitve but not a major or critical memleak. In a usual setup this would leak ~32 Bytes per mail. diff --git a/src/oomhelp.cpp b/src/oomhelp.cpp index 297fe0b..947ffce 100644 --- a/src/oomhelp.cpp +++ b/src/oomhelp.cpp @@ -979,6 +979,7 @@ put_pa_string (LPDISPATCH pDisp, const char *dasl_id, const char *value) { wchar_t *w_value = utf8_to_wchar (value); BSTR b_value = SysAllocString(w_value); + xfree (w_value); VARIANT var; VariantInit (&var); var.vt = VT_BSTR; commit 2c19657c31369e9791f6aae035331c3e8cf61cd8 Author: Andre Heinecke Date: Mon Jul 23 15:24:22 2018 +0200 Add caller debugging for wchar / utf8 convs * src/w32-gettext.cpp, src/w32-gettext.h (utf8_to_wchar), (wchar_to_utf8): Improve tracing for memory debug. -- We have some leaks here. diff --git a/src/w32-gettext.cpp b/src/w32-gettext.cpp index 9d9a515..edad1fd 100644 --- a/src/w32-gettext.cpp +++ b/src/w32-gettext.cpp @@ -1466,7 +1466,7 @@ native_to_wchar (const char *string) The result of calling this function with STRING set to NULL is not defined. */ wchar_t * -utf8_to_wchar (const char *string) +_utf8_to_wchar (const char *string) { int n; wchar_t *result; @@ -1495,7 +1495,7 @@ utf8_to_wchar (const char *string) The result of calling this function with STRING set to NULL is not defined. */ char * -wchar_to_utf8 (const wchar_t *string) +_wchar_to_utf8 (const wchar_t *string) { int n; char *result; diff --git a/src/w32-gettext.h b/src/w32-gettext.h index 7010586..7374ae9 100644 --- a/src/w32-gettext.h +++ b/src/w32-gettext.h @@ -64,10 +64,28 @@ static inline const char *gettext_localename (void) { return ""; } #endif /* !ENABLE_NLS */ -/* Conversion function. */ -char *wchar_to_utf8 (const wchar_t *string); -wchar_t *utf8_to_wchar (const char *string); +#define utf8_to_wchar(VAR1) ({wchar_t *retval; \ + retval = _utf8_to_wchar (VAR1); \ + if ((opt.enable_debug & DBG_OOM_EXTRA)) \ + { \ + log_debug ("%s:%s:%i wchar_t alloc %p", \ + SRCNAME, __func__, __LINE__, retval); \ + } \ +retval;}) + +#define wchar_to_utf8(VAR1) ({char *retval; \ + retval = _wchar_to_utf8 (VAR1); \ + if ((opt.enable_debug & DBG_OOM_EXTRA)) \ + { \ + log_debug ("%s:%s:%i char utf8 alloc %p", \ + SRCNAME, __func__, __LINE__, retval); \ + } \ +retval;}) + +/* Conversion function. */ +char *_wchar_to_utf8 (const wchar_t *string); +wchar_t *_utf8_to_wchar (const char *string); char *utf8_to_native (const char *string); char *native_to_utf8 (const char *string); commit 0d2d92689189178a14bd4c86bba6960667e1d6e6 Author: Andre Heinecke Date: Mon Jul 23 15:22:25 2018 +0200 Use static references for VARAINT_BOOL | BYREF * src/ribbon-callbacks.cpp (get_crypt_pressed), (get_is_details_enabled, get_is_crypto_mail): Reference a static. -- I really don't understand it but malloc'ing also seems wrong as we leak heap mem here. These references to static variables appear to work. diff --git a/src/ribbon-callbacks.cpp b/src/ribbon-callbacks.cpp index 42a020e..03d4d98 100644 --- a/src/ribbon-callbacks.cpp +++ b/src/ribbon-callbacks.cpp @@ -48,6 +48,12 @@ using namespace GpgME; +/* This is so super stupid. I bet even Microsft developers laugh + about the definition of VARIANT_BOOL. And then for COM we + have to pass pointers to this stuff. */ +static VARIANT_BOOL var_true = VARIANT_TRUE; +static VARIANT_BOOL var_false = VARIANT_FALSE; + /* Gets the context of a ribbon control. And prints some useful debug output */ HRESULT getContext (LPDISPATCH ctrl, LPDISPATCH *context) @@ -322,7 +328,7 @@ HRESULT get_crypt_pressed (LPDISPATCH ctrl, int flags, VARIANT *result, value = (get_gpgol_draft_info_flags (message) & flags) == flags; - *(result->pboolVal) = value ? VARIANT_TRUE : VARIANT_FALSE; + *(result->pboolVal) = value ? var_true: var_false; done: gpgol_release (context); @@ -534,8 +540,7 @@ HRESULT get_is_details_enabled (LPDISPATCH ctrl, VARIANT *result) } result->vt = VT_BOOL | VT_BYREF; - result->pboolVal = (VARIANT_BOOL*) xmalloc (sizeof (VARIANT_BOOL)); - *(result->pboolVal) = none_selected ? VARIANT_FALSE : VARIANT_TRUE; + result->pboolVal = none_selected ? &var_false : &var_true; TRACEPOINT; return S_OK; @@ -730,9 +735,8 @@ HRESULT get_is_crypto_mail (LPDISPATCH ctrl, VARIANT *result) MY_MAIL_GETTER result->vt = VT_BOOL | VT_BYREF; - result->pboolVal = (VARIANT_BOOL*) xmalloc (sizeof (VARIANT_BOOL)); - *(result->pboolVal) = (mail && (mail->isSigned () || mail->isEncrypted ())) ? - VARIANT_TRUE : VARIANT_FALSE; + result->pboolVal = mail && (mail->isSigned () || mail->isEncrypted ()) ? + &var_true : &var_false; TRACEPOINT; return S_OK; commit eb9236394ef217d908df44d9839b18c293ac0564 Author: Andre Heinecke Date: Mon Jul 23 15:21:14 2018 +0200 Fix unlikely error memleak * src/mapihel.cpp (mapi_get_message_content_type): Fix error handling meleak. diff --git a/src/mapihelp.cpp b/src/mapihelp.cpp index abf94a6..ecd45f8 100644 --- a/src/mapihelp.cpp +++ b/src/mapihelp.cpp @@ -3109,6 +3109,7 @@ mapi_get_message_content_type (LPMESSAGE message, log_error ("%s:%s: failed to get headers", SRCNAME, __func__); + rfc822parse_close (msg); return NULL; } ----------------------------------------------------------------------- Summary of changes: src/gpgoladdin.cpp | 1 + src/mail.cpp | 8 +------- src/mail.h | 3 --- src/mapihelp.cpp | 1 + src/oomhelp.cpp | 1 + src/ribbon-callbacks.cpp | 28 +++++++++++++++++++--------- src/w32-gettext.cpp | 4 ++-- src/w32-gettext.h | 24 +++++++++++++++++++++--- 8 files changed, 46 insertions(+), 24 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 23 16:33:23 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Mon, 23 Jul 2018 16:33:23 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-117-g333f175 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via 333f17572f1e414eb5a41d477d5187e12f3307bf (commit) via d4c0e8caf3ea75f56b7ccad49084324ab4741afa (commit) from 43cd17881983b02d90062bca8050f07c97fe325f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 333f17572f1e414eb5a41d477d5187e12f3307bf Author: Andre Heinecke Date: Mon Jul 23 16:32:32 2018 +0200 Fix orig body memleak in decryptVerify * src/mail.cpp (Mail::decryptVerify_o): Don't assign heap alloced data to std::string without free. diff --git a/src/mail.cpp b/src/mail.cpp index afad308..27fba3f 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -1022,7 +1022,14 @@ Mail::decryptVerify_o () if (opt.prefer_html) { - m_orig_body = get_oom_string (m_mailitem, "HTMLBody"); + char *tmp = get_oom_string (m_mailitem, "HTMLBody"); + if (!tmp) + { + TRACEPOINT; + return 1; + } + m_orig_body = tmp; + xfree (tmp); if (put_oom_string (m_mailitem, "HTMLBody", placeholder_buf)) { log_error ("%s:%s: Failed to modify html body of item.", @@ -1031,7 +1038,14 @@ Mail::decryptVerify_o () } else { - m_orig_body = get_oom_string (m_mailitem, "Body"); + char *tmp = get_oom_string (m_mailitem, "Body"); + if (!tmp) + { + TRACEPOINT; + return 1; + } + m_orig_body = tmp; + xfree (tmp); if (put_oom_string (m_mailitem, "Body", placeholder_buf)) { log_error ("%s:%s: Failed to modify body of item.", commit d4c0e8caf3ea75f56b7ccad49084324ab4741afa Author: Andre Heinecke Date: Mon Jul 23 16:31:45 2018 +0200 Fix memleak of plain body in collect_data * src/cryptcontroller.cpp (CryptController::collect_data): Fix leak. diff --git a/src/cryptcontroller.cpp b/src/cryptcontroller.cpp index d97e891..826dde4 100644 --- a/src/cryptcontroller.cpp +++ b/src/cryptcontroller.cpp @@ -153,8 +153,11 @@ CryptController::collect_data () sink->writefnc = sink_data_write; /* Collect the mime strucutre */ - if (add_body_and_attachments (sink, message, att_table, m_mail, - body, n_att_usable)) + int err = add_body_and_attachments (sink, message, att_table, m_mail, + body, n_att_usable); + xfree (body); + + if (err) { log_error ("%s:%s: Collecting body and attachments failed.", SRCNAME, __func__); ----------------------------------------------------------------------- Summary of changes: src/cryptcontroller.cpp | 7 +++++-- src/mail.cpp | 18 ++++++++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 24 08:41:37 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Tue, 24 Jul 2018 08:41:37 +0200 Subject: [git] GPGME - branch, master, updated. gpgme-1.11.1-108-ga6e5c8b Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, master has been updated via a6e5c8bf18696007c48c6f362aa355020fe82f21 (commit) from 4d1642b11ea64b8009a8720d9b59e89636d691d2 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit a6e5c8bf18696007c48c6f362aa355020fe82f21 Author: Andre Heinecke Date: Tue Jul 24 08:40:28 2018 +0200 cpp: Add safety checks for key update * lang/cpp/src/key.cpp (Key::update): Check that the key is not NULL. * lang/cpp/src/verificationresult.cpp (GpgME::Signature::key): Check for fingerprint. diff --git a/lang/cpp/src/key.cpp b/lang/cpp/src/key.cpp index 61b3eb7..8fc266f 100644 --- a/lang/cpp/src/key.cpp +++ b/lang/cpp/src/key.cpp @@ -347,6 +347,9 @@ const Key &Key::mergeWith(const Key &other) void Key::update() { + if (isNull() || !primaryFingerprint()) { + return; + } auto ctx = Context::createForProtocol(protocol()); if (!ctx) { return; diff --git a/lang/cpp/src/verificationresult.cpp b/lang/cpp/src/verificationresult.cpp index 2c42d07..fa8237a 100644 --- a/lang/cpp/src/verificationresult.cpp +++ b/lang/cpp/src/verificationresult.cpp @@ -406,7 +406,7 @@ GpgME::Key GpgME::Signature::key(bool search, bool update) const } GpgME::Key ret = key(); - if (ret.isNull() && search) { + if (ret.isNull() && search && fingerprint ()) { auto ctx = Context::createForProtocol (d->proto); if (ctx) { ctx->setKeyListMode(KeyListMode::Local | ----------------------------------------------------------------------- Summary of changes: lang/cpp/src/key.cpp | 3 +++ lang/cpp/src/verificationresult.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 24 08:42:16 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Tue, 24 Jul 2018 08:42:16 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-121-g4259c5d Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via 4259c5d63d43873733237abcf78a126e49effc9c (commit) via aa61e82d88aa984fb4ba92c37c60a6ae04916283 (commit) via bbcf8708c827b3a252013036a3d302101245722d (commit) via ec9387e439ce083298b56437ffeb494582ce1c26 (commit) from 333f17572f1e414eb5a41d477d5187e12f3307bf (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 4259c5d63d43873733237abcf78a126e49effc9c Author: Andre Heinecke Date: Tue Jul 24 08:10:29 2018 +0200 Return 0 for handled WindowMessages * src/windowmessages.cpp (gpgol_window_proc): Return 0 for messages handled by us. -- Does not make sense to call the defaultwindowproc for our own messages. diff --git a/src/windowmessages.cpp b/src/windowmessages.cpp index 84c66b5..5f90e37 100644 --- a/src/windowmessages.cpp +++ b/src/windowmessages.cpp @@ -38,6 +38,7 @@ static int invalidation_blocked = 0; LONG_PTR WINAPI gpgol_window_proc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { +// log_debug ("WMG: %x", (unsigned int) message); if (message == WM_USER + 42) { wm_ctx_t *ctx = (wm_ctx_t *) lParam; @@ -226,7 +227,7 @@ gpgol_window_proc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) log_debug ("%s:%s: Unknown msg %x", SRCNAME, __func__, ctx->wmsg_type); } - return DefWindowProc(hWnd, message, wParam, lParam); + return 0; } return DefWindowProc(hWnd, message, wParam, lParam); } @@ -414,6 +415,7 @@ gpgol_hook(int code, WPARAM wParam, LPARAM lParam) } */ break; default: +// log_debug ("WM: %x", (unsigned int) cwp->message); break; } return CallNextHookEx (NULL, code, wParam, lParam); commit aa61e82d88aa984fb4ba92c37c60a6ae04916283 Author: Andre Heinecke Date: Tue Jul 24 08:09:42 2018 +0200 Trace timing of sig key request * src/parsecontroller.cpp (ParseController::parse): Add tracepoints. diff --git a/src/parsecontroller.cpp b/src/parsecontroller.cpp index 20753b0..8dc0034 100644 --- a/src/parsecontroller.cpp +++ b/src/parsecontroller.cpp @@ -463,7 +463,9 @@ ParseController::parse() /* FIXME: This is very expensive. We need some caching here or reduce the information */ + TRACEPOINT; sig.key(true, true); + TRACEPOINT; if (!ultimate_keys_queried && (sig.validity() == Signature::Validity::Full || sig.validity() == Signature::Validity::Ultimate)) commit bbcf8708c827b3a252013036a3d302101245722d Author: Andre Heinecke Date: Tue Jul 24 08:08:02 2018 +0200 Log invalid skipped secret keys * src/keycache.cpp (locate_secret): Log invalid skipped keys. -- This might help in debug output if autoencrypt does not work for some. diff --git a/src/keycache.cpp b/src/keycache.cpp index 72eea28..a0eadba 100644 --- a/src/keycache.cpp +++ b/src/keycache.cpp @@ -32,6 +32,7 @@ #include #include +#include GPGRT_LOCK_DEFINE (keycache_lock); static KeyCache* singleton = nullptr; @@ -484,8 +485,13 @@ locate_secret (const char *addr, GpgME::Protocol proto) if (key.isRevoked() || key.isExpired() || key.isDisabled() || key.isInvalid()) { - log_mime_parser ("%s:%s: Skipping invalid secret key", - SRCNAME, __func__); + if ((opt.enable_debug & DBG_MIME_PARSER)) + { + std::stringstream ss; + ss << key; + log_mime_parser ("%s:%s: Skipping invalid secret key %s", + SRCNAME, __func__, ss.str().c_str()); + } continue; } if (proto == GpgME::OpenPGP) commit ec9387e439ce083298b56437ffeb494582ce1c26 Author: Andre Heinecke Date: Tue Jul 24 08:06:58 2018 +0200 Print parsed mail count in dbg output * src/mail.cpp (Mail::updateBody_o): Print parsed mail count. diff --git a/src/mail.cpp b/src/mail.cpp index 27fba3f..4ee4314 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -1322,12 +1322,14 @@ Mail::updateBody_o () return; } +static int parsed_count; + void Mail::parsing_done() { TRACEPOINT; - log_oom_extra ("Mail %p Parsing done for parser: %p", - this, m_parser.get()); + log_oom_extra ("Mail %p Parsing done for parser num %i: %p", + this, parsed_count++, m_parser.get()); if (!m_parser) { /* This should not happen but it happens when outlook ----------------------------------------------------------------------- Summary of changes: src/keycache.cpp | 10 ++++++++-- src/mail.cpp | 6 ++++-- src/parsecontroller.cpp | 2 ++ src/windowmessages.cpp | 4 +++- 4 files changed, 17 insertions(+), 5 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 24 10:06:51 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Tue, 24 Jul 2018 10:06:51 +0200 Subject: [git] GnuPG - branch, master, updated. gnupg-2.2.7-180-g9aa1b36 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 9aa1b368efd4edf51b6d056339bffb726de5162b (commit) from 1c9584dabb21b6ea5865316e6bad34576094921c (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 9aa1b368efd4edf51b6d056339bffb726de5162b Author: Werner Koch Date: Tue Jul 24 09:50:02 2018 +0200 gpg: Use 128 MiB as default AEAD chunk size. * g10/gpg.c (oDebugAllowLargeChunks): New. (opts): New option --debug-allow-large-chunks. (main): Implement that option. -- Signed-off-by: Werner Koch diff --git a/doc/gpg.texi b/doc/gpg.texi index 4cfd000..7c27fba 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -2258,9 +2258,8 @@ 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. +allowed value for @var{n} is 6 (64 byte) and the largest is the +default of 27 which creates chunks not larger than 128 MiB. @item --input-size-hint @var{n} @opindex input-size-hint @@ -2621,7 +2620,7 @@ to declare that a not yet standardized feature is used. @opindex disable-mdc These options are obsolete and have no effect since GnuPG 2.2.8. The MDC is always used unless the keys indicate that an AEAD algorithm can -be used in which case AEAD is used. But note: If the creation or of a +be used in which case AEAD is used. But note: If the creation of a legacy non-MDC message is exceptionally required, the option @option{--rfc2440} allows for this. @@ -2862,6 +2861,13 @@ 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. + at item --debug-allow-large-chunks + at opindex debug-allow-large-chunks +To facilitate in-memory decryption on the receiving site, the largest +recommended chunk size is 128 MiB (@code{--chunk-size 27}). This +option allows to specify a limit of up to 4 EiB (@code{--chunk-size +62}) for experiments. + @item --faked-system-time @var{epoch} @opindex faked-system-time This option is only useful for testing; it sets the system time back or diff --git a/g10/gpg.c b/g10/gpg.c index 600f844..36af918 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -225,6 +225,7 @@ enum cmd_and_opt_values oDebugAll, oDebugIOLBF, oDebugSetIobufSize, + oDebugAllowLargeChunks, oStatusFD, oStatusFile, oAttributeFD, @@ -634,6 +635,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oDebugAll, "debug-all", "@"), ARGPARSE_s_n (oDebugIOLBF, "debug-iolbf", "@"), ARGPARSE_s_u (oDebugSetIobufSize, "debug-set-iobuf-size", "@"), + ARGPARSE_s_u (oDebugAllowLargeChunks, "debug-allow-large-chunks", "@"), ARGPARSE_s_i (oStatusFD, "status-fd", "@"), ARGPARSE_s_s (oStatusFile, "status-file", "@"), ARGPARSE_s_i (oAttributeFD, "attribute-fd", "@"), @@ -2347,6 +2349,7 @@ main (int argc, char **argv) static int print_dane_records; static int print_pka_records; + static int allow_large_chunks; #ifdef __riscos__ @@ -2761,6 +2764,10 @@ main (int argc, char **argv) opt_set_iobuf_size_used = 1; break; + case oDebugAllowLargeChunks: + allow_large_chunks = 1; + break; + case oStatusFD: set_status_fd ( translate_sys2libc_fd_int (pargs.r.ret_int, 1) ); break; @@ -3884,15 +3891,15 @@ main (int argc, char **argv) /* 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. */ + opt.chunk_size = 27; /* Default to the suggested max of 128 MiB. */ 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) + else if (opt.chunk_size > (allow_large_chunks? 62 : 27)) { - opt.chunk_size = 62; + opt.chunk_size = (allow_large_chunks? 62 : 27); log_info (_("chunk size invalid - using %d\n"), opt.chunk_size); } ----------------------------------------------------------------------- Summary of changes: doc/gpg.texi | 14 ++++++++++---- g10/gpg.c | 13 ++++++++++--- 2 files changed, 20 insertions(+), 7 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 24 11:08:55 2018 From: cvs at cvs.gnupg.org (by Andre Heinecke) Date: Tue, 24 Jul 2018 11:08:55 +0200 Subject: [git] GpgOL - branch, master, updated. gpgol-2.2.0-128-ge4f0d5c Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG extension for MS Outlook". The branch, master has been updated via e4f0d5ca1ae0c27b4e52839c8ec6fd9d5cdda8e8 (commit) via 2353e5fd63e3877067dd7d638513b17c57a70802 (commit) via 67f3f9627a1cb058b762efa03653d3ada3056338 (commit) via 4074a157c304a0698a71500c0508db9b74d78fef (commit) from 87f6328dea01614ec6e9282f05c8f3eb35470d12 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit e4f0d5ca1ae0c27b4e52839c8ec6fd9d5cdda8e8 Author: Andre Heinecke Date: Tue Jul 24 11:07:45 2018 +0200 Minor cleanups * src/cryptcontroller.cpp, src/cryptcontroller.h: m_recipents is now a vector. diff --git a/src/cryptcontroller.cpp b/src/cryptcontroller.cpp index 826dde4..f6f1542 100644 --- a/src/cryptcontroller.cpp +++ b/src/cryptcontroller.cpp @@ -71,7 +71,7 @@ CryptController::CryptController (Mail *mail, bool encrypt, bool sign, memdbg_ctor ("CryptController"); log_debug ("%s:%s: CryptController ctor for %p encrypt %i sign %i inline %i.", SRCNAME, __func__, mail, encrypt, sign, mail->getDoPGPInline ()); - m_recipient_addrs = vector_to_cArray (mail->getCachedRecipients ()); + m_recipient_addrs = mail->getCachedRecipients (); } CryptController::~CryptController() @@ -79,7 +79,6 @@ CryptController::~CryptController() memdbg_dtor ("CryptController"); log_debug ("%s:%s:%p", SRCNAME, __func__, m_mail); - release_cArray (m_recipient_addrs); } int @@ -222,6 +221,7 @@ CryptController::lookup_fingerprints (const std::string &sigFpr, if (err) { log_error ("%s:%s: failed to start recipient keylisting", SRCNAME, __func__); + release_cArray (cRecps); return -1; } @@ -322,7 +322,7 @@ CryptController::resolve_keys_cached() if (m_encrypt) { const auto cached_sender = m_mail->getSender (); - auto recps = cArray_to_vector ((const char**) m_recipient_addrs); + auto recps = m_recipient_addrs; recps.push_back (cached_sender); m_recipients.clear(); @@ -479,9 +479,9 @@ CryptController::resolve_keys () { args.push_back (std::string ("--encrypt")); // Get the recipients that are cached from OOM - for (size_t i = 0; m_recipient_addrs && m_recipient_addrs[i]; i++) + for (const auto &addr: m_recipient_addrs) { - args.push_back (GpgME::UserID::addrSpecFromString (m_recipient_addrs[i])); + args.push_back (GpgME::UserID::addrSpecFromString (addr.c_str())); } } diff --git a/src/cryptcontroller.h b/src/cryptcontroller.h index 4ba57d9..8a3ffe5 100644 --- a/src/cryptcontroller.h +++ b/src/cryptcontroller.h @@ -94,7 +94,7 @@ private: GpgME::Key m_signer_key; std::vector m_recipients; std::unique_ptr m_overlay; - char **m_recipient_addrs; + std::vector m_recipient_addrs; }; #endif commit 2353e5fd63e3877067dd7d638513b17c57a70802 Author: Andre Heinecke Date: Tue Jul 24 11:06:56 2018 +0200 Fix memory leak when opening options * src/addin-options.cpp (open_gpgolgui): Release cArray. diff --git a/src/addin-options.cpp b/src/addin-options.cpp index 6d3da45..f81bed8 100644 --- a/src/addin-options.cpp +++ b/src/addin-options.cpp @@ -119,6 +119,7 @@ open_gpgolgui (LPVOID arg) (GpgME::Context::SpawnFlags) ( GpgME::Context::SpawnAllowSetFg | GpgME::Context::SpawnShowWindow)); + release_cArray (cargs); if (err) { log_error ("%s:%s: Err code: %i asString: %s", commit 67f3f9627a1cb058b762efa03653d3ada3056338 Author: Andre Heinecke Date: Tue Jul 24 10:25:17 2018 +0200 Auto update german po file formatting * po/de.po: Update. diff --git a/po/de.po b/po/de.po index e456a05..c392396 100644 --- a/po/de.po +++ b/po/de.po @@ -94,10 +94,9 @@ msgid "" "This changes the trust model to \"tofu+pgp\" which tracks the history of key " "usage. Automated trust can never exceed level 2." msgstr "" -"Dies ?ndert das Vertrauensmodell auf \"tofu+pgp\", welches die" -" Kommunikationshistorie " -"des Schl?ssels ber?cksichtigt. Automatisiertes vertrauen kann niemals" -" level 2 ?bersteigen." +"Dies ?ndert das Vertrauensmodell auf \"tofu+pgp\", welches die " +"Kommunikationshistorie des Schl?ssels ber?cksichtigt. Automatisiertes " +"vertrauen kann niemals level 2 ?bersteigen." #: src/addin-options.cpp:62 msgid "experimental" @@ -123,8 +122,8 @@ msgstr "W?hlt die Signieren Option f?r alle neuen Mails. " msgid "" "Toggles sign, encrypt options if the original mail was signed or encrypted." msgstr "" -"W?hlt signieren, verschl?sseln je nachdem ob die original Mail signiert oder" -" verschl?sselt war." +"W?hlt signieren, verschl?sseln je nachdem ob die original Mail signiert oder " +"verschl?sselt war." #: src/addin-options.cpp:67 msgid "" @@ -132,11 +131,10 @@ msgid "" "encoding, the deprecated PGP/Inline is used.\n" "This can be required for compatibility but should generally not be used." msgstr "" -"Anstelle des PGP/MIME Formats, welches Anh?nge und encoding richtig" -" behandelt, " -"das veraltete PGP/Inline verwenden.\n" -"Dies kann f?r kompatibilit?t manchmal n?tig sein, sollte aber generell nicht" -" verwendet werden." +"Anstelle des PGP/MIME Formats, welches Anh?nge und encoding richtig " +"behandelt, das veraltete PGP/Inline verwenden.\n" +"Dies kann f?r kompatibilit?t manchmal n?tig sein, sollte aber generell nicht " +"verwendet werden." #: src/common.cpp:768 msgid "GpgOL Error" commit 4074a157c304a0698a71500c0508db9b74d78fef Author: Andre Heinecke Date: Tue Jul 24 10:24:34 2018 +0200 Fix return value of is_crypt_pressed * src/ribbon-callbacks.cpp (get_crypt_pressed): Fix return value. diff --git a/src/ribbon-callbacks.cpp b/src/ribbon-callbacks.cpp index d2310e0..fa10c8c 100644 --- a/src/ribbon-callbacks.cpp +++ b/src/ribbon-callbacks.cpp @@ -327,7 +327,7 @@ HRESULT get_crypt_pressed (LPDISPATCH ctrl, int flags, VARIANT *result, value = (get_gpgol_draft_info_flags (message) & flags) == flags; - *(result->pboolVal) = value ? var_true: var_false; + result->pboolVal = value ? &var_true: &var_false; done: gpgol_release (context); ----------------------------------------------------------------------- Summary of changes: po/de.po | 20 +++++++++----------- src/addin-options.cpp | 1 + src/cryptcontroller.cpp | 10 +++++----- src/cryptcontroller.h | 2 +- src/ribbon-callbacks.cpp | 2 +- 5 files changed, 17 insertions(+), 18 deletions(-) hooks/post-receive -- GnuPG extension for MS Outlook http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 24 14:57:37 2018 From: cvs at cvs.gnupg.org (by Maximilian Krambach) Date: Tue, 24 Jul 2018 14:57:37 +0200 Subject: [git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-79-g4b343c4 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, javascript-binding has been updated via 4b343c4e339862a5faf8dd20590a3c4592fb6abb (commit) via 040b1ed40ada7c9ce095dec696406aea730e3766 (commit) from a965e3e0b89521ad4f3898a8483161624c2e5848 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 4b343c4e339862a5faf8dd20590a3c4592fb6abb Author: Maximilian Krambach Date: Tue Jul 24 14:56:33 2018 +0200 js: include armored Key in import callback -- * The import answer now also directly contains the armored Key as Key property, without need to refresh the Key object created in the answer. This allows for direct comparision of input and output. * BrowserTestExtension: added test for that import callback diff --git a/lang/js/BrowserTestExtension/tests/KeyImportExport.js b/lang/js/BrowserTestExtension/tests/KeyImportExport.js index 4a53c7a..ed307b3 100644 --- a/lang/js/BrowserTestExtension/tests/KeyImportExport.js +++ b/lang/js/BrowserTestExtension/tests/KeyImportExport.js @@ -83,6 +83,32 @@ describe('Key importing', function () { }); }); }); + + it('Import result feedback', function(done){ + let prm = Gpgmejs.init(); + prm.then(function (context) { + context.Keyring.getKeys(ImportablePublicKey.fingerprint).then( + function(result){ + expect(result).to.be.an('array'); + expect(result.length).to.equal(0); + context.Keyring.importKey(ImportablePublicKey.key, true) + .then(function(result){ + expect(result).to.be.an('object'); + expect(result.Keys[0]).to.be.an('object'); + expect(result.Keys[0].key.fingerprint).to.equal( + ImportablePublicKey.fingerprint); + expect(result.Keys[0].status).to.equal('newkey'); + result.Keys[0].key.getArmor().then(function(armor){ + expect(armor).to.be.a('string'); + result.Keys[0].key.delete().then(function(){ + done(); + }); + }); + }); + }); + }); + }); + it('exporting armored Key with getKeysArmored', function (done) { let prm = Gpgmejs.init(); const fpr = inputvalues.encrypt.good.fingerprint; diff --git a/lang/js/src/Key.js b/lang/js/src/Key.js index 30f507c..b024a77 100644 --- a/lang/js/src/Key.js +++ b/lang/js/src/Key.js @@ -141,7 +141,7 @@ export class GPGME_Key { * during a session. The key still can be reloaded by invoking * {@link refreshKey}. * @returns {*|Promise<*>} the value (Boolean, String, Array, Object). - * If 'cached' is true, the value will be resolved as a Promise. + * If 'cached' is false, the value will be resolved as a Promise. */ get(property, cached=true) { if (cached === false) { @@ -194,8 +194,11 @@ export class GPGME_Key { if (result.keys.length === 1){ me.setKeyData(result.keys[0]); me.getHasSecret().then(function(){ - //TODO retrieve armored Key - resolve(me); + me.getArmor().then(function(){ + resolve(me); + }, function(error){ + reject(error); + }); }, function(error){ reject(error); }); commit 040b1ed40ada7c9ce095dec696406aea730e3766 Author: Maximilian Krambach Date: Tue Jul 24 14:50:54 2018 +0200 js: Fix wrong encoding in received error messages -- * The libgpg error strings arrive in the browser in a different encoding than used by browsers. Escaping and then decoding it should cover most languages in the supported browsers. diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index ef54dd6..d89fa72 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -240,7 +240,8 @@ class Answer{ switch (key) { case 'type': if (_decodedResponse.type === 'error'){ - return (gpgme_error('GNUPG_ERROR', _decodedResponse.msg)); + return (gpgme_error('GNUPG_ERROR', + decodeURIComponent(escape(_decodedResponse.msg)))); } else if (poa.type.indexOf(_decodedResponse.type) < 0){ return gpgme_error('CONN_UNEXPECTED_ANSWER'); } ----------------------------------------------------------------------- Summary of changes: .../BrowserTestExtension/tests/KeyImportExport.js | 26 ++++++++++++++++++++++ lang/js/src/Connection.js | 3 ++- lang/js/src/Key.js | 9 +++++--- 3 files changed, 34 insertions(+), 4 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Wed Jul 25 14:44:40 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Wed, 25 Jul 2018 14:44:40 +0200 Subject: [git] GnuPG - branch, master, updated. gnupg-2.2.7-181-gbd4048c Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via bd4048c533165fd82340354d7229fcc2220db5a5 (commit) from 9aa1b368efd4edf51b6d056339bffb726de5162b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit bd4048c533165fd82340354d7229fcc2220db5a5 Author: Werner Koch Date: Wed Jul 25 14:35:04 2018 +0200 dirmngr: Print a WARNING status for DNS config problems. * dirmngr/dirmngr-status.h: New. * dirmngr/dirmngr.h: Include dirmngr-status.h and move some prototypes to that file. * dirmngr/t-support.c: New. * dirmngr/Makefile.am (dirmngr_SOURCES): Add dirmngr-status.h. (t_common_src): Add t-support.c. * dirmngr/server.c (dirmngr_status_printf): Bypass if CTRL is NULL. * dirmngr/dns-stuff.c: Include dirmngr-status.h. (libdns_init): Print WARNING status line. Change call callers to take and pass a CTRL argument. * g10/call-dirmngr.c (ks_status_cb): Print info for new WARNING status. -- To test this you can change RESOLV_CONF_NAME in dns-stuff.c and run gpg --recv-key -v SOMETHING. Signed-off-by: Werner Koch diff --git a/dirmngr/Makefile.am b/dirmngr/Makefile.am index 43f59bd..22b8c1a 100644 --- a/dirmngr/Makefile.am +++ b/dirmngr/Makefile.am @@ -62,7 +62,7 @@ dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c \ domaininfo.c \ workqueue.c \ loadswdb.c \ - cdb.h cdblib.c misc.c dirmngr-err.h \ + cdb.h cdblib.c misc.c dirmngr-err.h dirmngr-status.h \ ocsp.c ocsp.h validate.c validate.h \ dns-stuff.c dns-stuff.h \ http.c http.h http-common.c http-common.h http-ntbtls.c \ @@ -111,7 +111,7 @@ dirmngr_client_LDADD = $(libcommon) \ dirmngr_client_LDFLAGS = $(extra_bin_ldflags) -t_common_src = t-support.h +t_common_src = t-support.h t-support.c if USE_LIBDNS t_common_src += dns.c dns.h endif diff --git a/dirmngr/dirmngr-status.h b/dirmngr/dirmngr-status.h new file mode 100644 index 0000000..2c3fd78 --- /dev/null +++ b/dirmngr/dirmngr-status.h @@ -0,0 +1,39 @@ +/* dirmngr-status.h - Status code helper functions for dirmnmgr. + * Copyright (C) 2004, 2014, 2015, 2018 g10 Code GmbH + * + * 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 . + * + * SPDX-License-Identifier: GPL-3.0+ + */ + +/* We keep them separate so that we don't always need to include the + * entire dirmngr.h */ + +#ifndef DIRMNGR_STATUS_H +#define DIRMNGR_STATUS_H + + +/*-- server.c --*/ +gpg_error_t dirmngr_status (ctrl_t ctrl, const char *keyword, ...); +gpg_error_t dirmngr_status_help (ctrl_t ctrl, const char *text); +gpg_error_t dirmngr_status_helpf (ctrl_t ctrl, const char *format, + ...) GPGRT_ATTR_PRINTF(2,3); +gpg_error_t dirmngr_status_printf (ctrl_t ctrl, const char *keyword, + const char *format, + ...) GPGRT_ATTR_PRINTF(3,4); + + +#endif /* DIRMNGR_STATUS_H */ diff --git a/dirmngr/dirmngr.h b/dirmngr/dirmngr.h index 5189f93..edaf463 100644 --- a/dirmngr/dirmngr.h +++ b/dirmngr/dirmngr.h @@ -36,6 +36,7 @@ #include "../common/sysutils.h" /* (gnupg_fd_t) */ #include "../common/asshelp.h" /* (assuan_context_t) */ #include "../common/i18n.h" +#include "dirmngr-status.h" #include "http.h" /* (parsed_uri_t) */ /* This objects keeps information about a particular LDAP server and @@ -229,13 +230,6 @@ gpg_error_t get_istrusted_from_client (ctrl_t ctrl, const char *hexfpr); int dirmngr_assuan_log_monitor (assuan_context_t ctx, unsigned int cat, const char *msg); void start_command_handler (gnupg_fd_t fd, unsigned int session_id); -gpg_error_t dirmngr_status (ctrl_t ctrl, const char *keyword, ...); -gpg_error_t dirmngr_status_help (ctrl_t ctrl, const char *text); -gpg_error_t dirmngr_status_helpf (ctrl_t ctrl, const char *format, - ...) GPGRT_ATTR_PRINTF(2,3); -gpg_error_t dirmngr_status_printf (ctrl_t ctrl, const char *keyword, - const char *format, - ...) GPGRT_ATTR_PRINTF(3,4); gpg_error_t dirmngr_tick (ctrl_t ctrl); /*-- http-ntbtls.c --*/ diff --git a/dirmngr/dns-stuff.c b/dirmngr/dns-stuff.c index ffac816..09b17c0 100644 --- a/dirmngr/dns-stuff.c +++ b/dirmngr/dns-stuff.c @@ -73,6 +73,7 @@ #include "./dirmngr-err.h" #include "../common/util.h" #include "../common/host2net.h" +#include "dirmngr-status.h" #include "dns-stuff.h" #ifdef USE_NPTH @@ -433,12 +434,13 @@ resolv_conf_changed_p (void) /* Initialize libdns. Returns 0 on success; prints a diagnostic and * returns an error code on failure. */ static gpg_error_t -libdns_init (void) +libdns_init (ctrl_t ctrl) { gpg_error_t err; struct libdns_s ld; int derr; char *cfgstr = NULL; + const char *fname = NULL; if (libdns.resolv_conf) return 0; /* Already initialized. */ @@ -532,7 +534,6 @@ libdns_init (void) xfree (ninfo); #else /* Unix */ - const char *fname; fname = RESOLV_CONF_NAME; resolv_conf_changed_p (); /* Reset timestamp. */ @@ -622,6 +623,7 @@ libdns_init (void) { err = libdns_error_to_gpg_error (derr); log_error ("failed to load DNS hints: %s\n", gpg_strerror (err)); + fname = "[dns hints]"; goto leave; } @@ -632,6 +634,14 @@ libdns_init (void) log_debug ("dns: libdns initialized%s\n", tor_mode?" (tor mode)":""); leave: + if (!fname) + fname = cfgstr; + if (err && fname) + dirmngr_status_printf (ctrl, "WARNING", + "dns_config_problem %u" + " error accessing '%s': %s <%s>", + err, fname, gpg_strerror (err), gpg_strsource (err)); + xfree (cfgstr); return err; } @@ -686,7 +696,7 @@ reload_dns_stuff (int force) * failure an error code is returned and NULL stored at R_RES. */ static gpg_error_t -libdns_res_open (struct dns_resolver **r_res) +libdns_res_open (ctrl_t ctrl, struct dns_resolver **r_res) { gpg_error_t err; struct dns_resolver *res; @@ -708,7 +718,7 @@ libdns_res_open (struct dns_resolver **r_res) libdns_deinit (); } - err = libdns_init (); + err = libdns_init (ctrl); if (err) return err; @@ -790,7 +800,7 @@ libdns_res_wait (struct dns_resolver *res) #ifdef USE_LIBDNS static gpg_error_t -resolve_name_libdns (const char *name, unsigned short port, +resolve_name_libdns (ctrl_t ctrl, const char *name, unsigned short port, int want_family, int want_socktype, dns_addrinfo_t *r_dai, char **r_canonname) { @@ -823,7 +833,7 @@ resolve_name_libdns (const char *name, unsigned short port, portstr = portstr_; } - err = libdns_res_open (&res); + err = libdns_res_open (ctrl, &res); if (err) goto leave; @@ -935,7 +945,7 @@ resolve_name_libdns (const char *name, unsigned short port, /* Resolve a name using the standard system function. */ static gpg_error_t -resolve_name_standard (const char *name, unsigned short port, +resolve_name_standard (ctrl_t ctrl, const char *name, unsigned short port, int want_family, int want_socktype, dns_addrinfo_t *r_dai, char **r_canonname) { @@ -981,7 +991,7 @@ resolve_name_standard (const char *name, unsigned short port, CNAME redirection again. */ char *cname; - if (get_dns_cname (name, &cname)) + if (get_dns_cname (ctrl, name, &cname)) goto leave; /* Still no success. */ ret = getaddrinfo (cname, *portstr? portstr : NULL, &hints, &aibuf); @@ -1057,7 +1067,7 @@ resolve_name_standard (const char *name, unsigned short port, is stored there as a malloced string; if that name is not available NULL is stored. */ gpg_error_t -resolve_dns_name (const char *name, unsigned short port, +resolve_dns_name (ctrl_t ctrl, const char *name, unsigned short port, int want_family, int want_socktype, dns_addrinfo_t *r_ai, char **r_canonname) { @@ -1066,15 +1076,15 @@ resolve_dns_name (const char *name, unsigned short port, #ifdef USE_LIBDNS if (!standard_resolver) { - err = resolve_name_libdns (name, port, want_family, want_socktype, + err = resolve_name_libdns (ctrl, name, port, want_family, want_socktype, r_ai, r_canonname); if (err && libdns_switch_port_p (err)) - err = resolve_name_libdns (name, port, want_family, want_socktype, + err = resolve_name_libdns (ctrl, name, port, want_family, want_socktype, r_ai, r_canonname); } else #endif /*USE_LIBDNS*/ - err = resolve_name_standard (name, port, want_family, want_socktype, + err = resolve_name_standard (ctrl, name, port, want_family, want_socktype, r_ai, r_canonname); if (opt_debug) log_debug ("dns: resolve_dns_name(%s): %s\n", name, gpg_strerror (err)); @@ -1085,7 +1095,8 @@ resolve_dns_name (const char *name, unsigned short port, #ifdef USE_LIBDNS /* Resolve an address using libdns. */ static gpg_error_t -resolve_addr_libdns (const struct sockaddr_storage *addr, int addrlen, +resolve_addr_libdns (ctrl_t ctrl, + const struct sockaddr_storage *addr, int addrlen, unsigned int flags, char **r_name) { gpg_error_t err; @@ -1117,7 +1128,7 @@ resolve_addr_libdns (const struct sockaddr_storage *addr, int addrlen, goto leave; - err = libdns_res_open (&res); + err = libdns_res_open (ctrl, &res); if (err) goto leave; @@ -1281,7 +1292,8 @@ resolve_addr_standard (const struct sockaddr_storage *addr, int addrlen, /* A wrapper around getnameinfo. */ gpg_error_t -resolve_dns_addr (const struct sockaddr_storage *addr, int addrlen, +resolve_dns_addr (ctrl_t ctrl, + const struct sockaddr_storage *addr, int addrlen, unsigned int flags, char **r_name) { gpg_error_t err; @@ -1290,9 +1302,9 @@ resolve_dns_addr (const struct sockaddr_storage *addr, int addrlen, /* Note that we divert to the standard resolver for NUMERICHOST. */ if (!standard_resolver && !(flags & DNS_NUMERICHOST)) { - err = resolve_addr_libdns (addr, addrlen, flags, r_name); + err = resolve_addr_libdns (ctrl, addr, addrlen, flags, r_name); if (err && libdns_switch_port_p (err)) - err = resolve_addr_libdns (addr, addrlen, flags, r_name); + err = resolve_addr_libdns (ctrl, addr, addrlen, flags, r_name); } else #endif /*USE_LIBDNS*/ @@ -1390,7 +1402,7 @@ is_onion_address (const char *name) /* libdns version of get_dns_cert. */ #ifdef USE_LIBDNS static gpg_error_t -get_dns_cert_libdns (const char *name, int want_certtype, +get_dns_cert_libdns (ctrl_t ctrl, const char *name, int want_certtype, void **r_key, size_t *r_keylen, unsigned char **r_fpr, size_t *r_fprlen, char **r_url) { @@ -1410,7 +1422,7 @@ get_dns_cert_libdns (const char *name, int want_certtype, : (want_certtype - DNS_CERTTYPE_RRBASE)); - err = libdns_res_open (&res); + err = libdns_res_open (ctrl, &res); if (err) goto leave; @@ -1776,7 +1788,7 @@ get_dns_cert_standard (const char *name, int want_certtype, supported certtypes only records with this certtype are considered and the first found is returned. (R_KEY,R_KEYLEN) are optional. */ gpg_error_t -get_dns_cert (const char *name, int want_certtype, +get_dns_cert (ctrl_t ctrl, const char *name, int want_certtype, void **r_key, size_t *r_keylen, unsigned char **r_fpr, size_t *r_fprlen, char **r_url) { @@ -1793,10 +1805,10 @@ get_dns_cert (const char *name, int want_certtype, #ifdef USE_LIBDNS if (!standard_resolver) { - err = get_dns_cert_libdns (name, want_certtype, r_key, r_keylen, + err = get_dns_cert_libdns (ctrl, name, want_certtype, r_key, r_keylen, r_fpr, r_fprlen, r_url); if (err && libdns_switch_port_p (err)) - err = get_dns_cert_libdns (name, want_certtype, r_key, r_keylen, + err = get_dns_cert_libdns (ctrl, name, want_certtype, r_key, r_keylen, r_fpr, r_fprlen, r_url); } else @@ -1828,7 +1840,8 @@ priosort(const void *a,const void *b) * R_COUNT. */ #ifdef USE_LIBDNS static gpg_error_t -getsrv_libdns (const char *name, struct srventry **list, unsigned int *r_count) +getsrv_libdns (ctrl_t ctrl, + const char *name, struct srventry **list, unsigned int *r_count) { gpg_error_t err; struct dns_resolver *res = NULL; @@ -1839,7 +1852,7 @@ getsrv_libdns (const char *name, struct srventry **list, unsigned int *r_count) int derr; unsigned int srvcount = 0; - err = libdns_res_open (&res); + err = libdns_res_open (ctrl, &res); if (err) goto leave; @@ -2058,7 +2071,8 @@ getsrv_standard (const char *name, * we do not return NONAME but simply store 0 at R_COUNT. On error an * error code is returned and 0 stored at R_COUNT. */ gpg_error_t -get_dns_srv (const char *name, const char *service, const char *proto, +get_dns_srv (ctrl_t ctrl, + const char *name, const char *service, const char *proto, struct srventry **list, unsigned int *r_count) { gpg_error_t err; @@ -2087,9 +2101,9 @@ get_dns_srv (const char *name, const char *service, const char *proto, #ifdef USE_LIBDNS if (!standard_resolver) { - err = getsrv_libdns (name, list, &srvcount); + err = getsrv_libdns (ctrl, name, list, &srvcount); if (err && libdns_switch_port_p (err)) - err = getsrv_libdns (name, list, &srvcount); + err = getsrv_libdns (ctrl, name, list, &srvcount); } else #endif /*USE_LIBDNS*/ @@ -2194,7 +2208,7 @@ get_dns_srv (const char *name, const char *service, const char *proto, #ifdef USE_LIBDNS /* libdns version of get_dns_cname. */ gpg_error_t -get_dns_cname_libdns (const char *name, char **r_cname) +get_dns_cname_libdns (ctrl_t ctrl, const char *name, char **r_cname) { gpg_error_t err; struct dns_resolver *res; @@ -2202,7 +2216,7 @@ get_dns_cname_libdns (const char *name, char **r_cname) struct dns_cname cname; int derr; - err = libdns_res_open (&res); + err = libdns_res_open (ctrl, &res); if (err) goto leave; @@ -2347,7 +2361,7 @@ get_dns_cname_standard (const char *name, char **r_cname) gpg_error_t -get_dns_cname (const char *name, char **r_cname) +get_dns_cname (ctrl_t ctrl, const char *name, char **r_cname) { gpg_error_t err; @@ -2356,9 +2370,9 @@ get_dns_cname (const char *name, char **r_cname) #ifdef USE_LIBDNS if (!standard_resolver) { - err = get_dns_cname_libdns (name, r_cname); + err = get_dns_cname_libdns (ctrl, name, r_cname); if (err && libdns_switch_port_p (err)) - err = get_dns_cname_libdns (name, r_cname); + err = get_dns_cname_libdns (ctrl, name, r_cname); return err; } #endif /*USE_LIBDNS*/ diff --git a/dirmngr/dns-stuff.h b/dirmngr/dns-stuff.h index 612b2e5..06a4312 100644 --- a/dirmngr/dns-stuff.h +++ b/dirmngr/dns-stuff.h @@ -137,12 +137,14 @@ void reload_dns_stuff (int force); void free_dns_addrinfo (dns_addrinfo_t ai); /* Function similar to getaddrinfo. */ -gpg_error_t resolve_dns_name (const char *name, unsigned short port, +gpg_error_t resolve_dns_name (ctrl_t ctrl, + const char *name, unsigned short port, int want_family, int want_socktype, dns_addrinfo_t *r_dai, char **r_canonname); /* Function similar to getnameinfo. */ -gpg_error_t resolve_dns_addr (const struct sockaddr_storage *addr, int addrlen, +gpg_error_t resolve_dns_addr (ctrl_t ctrl, + const struct sockaddr_storage *addr, int addrlen, unsigned int flags, char **r_name); /* Return true if NAME is a numerical IP address. */ @@ -152,16 +154,18 @@ int is_ip_address (const char *name); int is_onion_address (const char *name); /* Get the canonical name for NAME. */ -gpg_error_t get_dns_cname (const char *name, char **r_cname); +gpg_error_t get_dns_cname (ctrl_t ctrl, const char *name, char **r_cname); /* Return a CERT record or an arbitrary RR. */ -gpg_error_t get_dns_cert (const char *name, int want_certtype, +gpg_error_t get_dns_cert (ctrl_t ctrl, + const char *name, int want_certtype, void **r_key, size_t *r_keylen, unsigned char **r_fpr, size_t *r_fprlen, char **r_url); /* Return an array of SRV records. */ -gpg_error_t get_dns_srv (const char *name, +gpg_error_t get_dns_srv (ctrl_t ctrl, + const char *name, const char *service, const char *proto, struct srventry **list, unsigned int *r_count); diff --git a/dirmngr/http.c b/dirmngr/http.c index 049aefc..5fb7eed 100644 --- a/dirmngr/http.c +++ b/dirmngr/http.c @@ -2,7 +2,7 @@ * Copyright (C) 1999, 2001, 2002, 2003, 2004, 2006, 2009, 2010, * 2011 Free Software Foundation, Inc. * Copyright (C) 2014 Werner Koch - * Copyright (C) 2015-2017 g10 Code GmbH + * Copyright (C) 2015-2018 g10 Code GmbH * * This file is part of GnuPG. * @@ -152,14 +152,15 @@ static int remove_escapes (char *string); static int insert_escapes (char *buffer, const char *string, const char *special); static uri_tuple_t parse_tuple (char *string); -static gpg_error_t send_request (http_t hd, const char *httphost, +static gpg_error_t send_request (ctrl_t ctrl, http_t hd, const char *httphost, const char *auth,const char *proxy, const char *srvtag, unsigned int timeout, strlist_t headers); static char *build_rel_path (parsed_uri_t uri); static gpg_error_t parse_response (http_t hd); -static gpg_error_t connect_server (const char *server, unsigned short port, +static gpg_error_t connect_server (ctrl_t ctrl, + const char *server, unsigned short port, unsigned int flags, const char *srvtag, unsigned int timeout, assuan_fd_t *r_sock); static gpgrt_ssize_t read_server (assuan_fd_t sock, void *buffer, size_t size); @@ -937,7 +938,7 @@ http_session_set_timeout (http_session_t sess, unsigned int timeout) If HTTPHOST is not NULL it is used for the Host header instead of a Host header derived from the URL. */ gpg_error_t -http_open (http_t *r_hd, http_req_t reqtype, const char *url, +http_open (ctrl_t ctrl, http_t *r_hd, http_req_t reqtype, const char *url, const char *httphost, const char *auth, unsigned int flags, const char *proxy, http_session_t session, const char *srvtag, strlist_t headers) @@ -961,7 +962,7 @@ http_open (http_t *r_hd, http_req_t reqtype, const char *url, err = parse_uri (&hd->uri, url, 0, !!(flags & HTTP_FLAG_FORCE_TLS)); if (!err) - err = send_request (hd, httphost, auth, proxy, srvtag, + err = send_request (ctrl, hd, httphost, auth, proxy, srvtag, hd->session? hd->session->connect_timeout : 0, headers); @@ -985,7 +986,8 @@ http_open (http_t *r_hd, http_req_t reqtype, const char *url, this http abstraction layer. This has the advantage of providing service tags and an estream interface. TIMEOUT is in milliseconds. */ gpg_error_t -http_raw_connect (http_t *r_hd, const char *server, unsigned short port, +http_raw_connect (ctrl_t ctrl, http_t *r_hd, + const char *server, unsigned short port, unsigned int flags, const char *srvtag, unsigned int timeout) { gpg_error_t err = 0; @@ -1021,7 +1023,8 @@ http_raw_connect (http_t *r_hd, const char *server, unsigned short port, { assuan_fd_t sock; - err = connect_server (server, port, hd->flags, srvtag, timeout, &sock); + err = connect_server (ctrl, server, port, + hd->flags, srvtag, timeout, &sock); if (err) { xfree (hd); @@ -1174,14 +1177,14 @@ http_wait_response (http_t hd) be used as an HTTP proxy and any enabled $http_proxy gets ignored. */ gpg_error_t -http_open_document (http_t *r_hd, const char *document, +http_open_document (ctrl_t ctrl, http_t *r_hd, const char *document, const char *auth, unsigned int flags, const char *proxy, http_session_t session, const char *srvtag, strlist_t headers) { gpg_error_t err; - err = http_open (r_hd, HTTP_REQ_GET, document, NULL, auth, flags, + err = http_open (ctrl, r_hd, HTTP_REQ_GET, document, NULL, auth, flags, proxy, session, srvtag, headers); if (err) return err; @@ -1712,7 +1715,7 @@ is_hostname_port (const char *string) * Returns 0 if the request was successful */ static gpg_error_t -send_request (http_t hd, const char *httphost, const char *auth, +send_request (ctrl_t ctrl, http_t hd, const char *httphost, const char *auth, const char *proxy, const char *srvtag, unsigned int timeout, strlist_t headers) { @@ -1859,14 +1862,16 @@ send_request (http_t hd, const char *httphost, const char *auth, } } - err = connect_server (*uri->host ? uri->host : "localhost", + err = connect_server (ctrl, + *uri->host ? uri->host : "localhost", uri->port ? uri->port : 80, hd->flags, NULL, timeout, &sock); http_release_parsed_uri (uri); } else { - err = connect_server (server, port, hd->flags, srvtag, timeout, &sock); + err = connect_server (ctrl, + server, port, hd->flags, srvtag, timeout, &sock); } if (err) @@ -2870,7 +2875,7 @@ connect_with_timeout (assuan_fd_t sock, * function tries to connect to all known addresses and the timeout is * for each one. */ static gpg_error_t -connect_server (const char *server, unsigned short port, +connect_server (ctrl_t ctrl, const char *server, unsigned short port, unsigned int flags, const char *srvtag, unsigned int timeout, assuan_fd_t *r_sock) { @@ -2923,7 +2928,7 @@ connect_server (const char *server, unsigned short port, /* Do the SRV thing */ if (srvtag) { - err = get_dns_srv (server, srvtag, NULL, &serverlist, &srvcount); + err = get_dns_srv (ctrl, server, srvtag, NULL, &serverlist, &srvcount); if (err) log_info ("getting '%s' SRV for '%s' failed: %s\n", srvtag, server, gpg_strerror (err)); @@ -2953,7 +2958,8 @@ connect_server (const char *server, unsigned short port, if (opt_debug) log_debug ("http.c:connect_server: trying name='%s' port=%hu\n", serverlist[srv].target, port); - err = resolve_dns_name (serverlist[srv].target, port, 0, SOCK_STREAM, + err = resolve_dns_name (ctrl, + serverlist[srv].target, port, 0, SOCK_STREAM, &aibuf, NULL); if (err) { diff --git a/dirmngr/http.h b/dirmngr/http.h index 4cfb4c8..a86abbe 100644 --- a/dirmngr/http.h +++ b/dirmngr/http.h @@ -135,12 +135,12 @@ gpg_error_t http_parse_uri (parsed_uri_t *ret_uri, const char *uri, void http_release_parsed_uri (parsed_uri_t uri); -gpg_error_t http_raw_connect (http_t *r_hd, +gpg_error_t http_raw_connect (ctrl_t ctrl, http_t *r_hd, const char *server, unsigned short port, unsigned int flags, const char *srvtag, unsigned int timeout); -gpg_error_t http_open (http_t *r_hd, http_req_t reqtype, +gpg_error_t http_open (ctrl_t ctrl, http_t *r_hd, http_req_t reqtype, const char *url, const char *httphost, const char *auth, @@ -156,7 +156,7 @@ gpg_error_t http_wait_response (http_t hd); void http_close (http_t hd, int keep_read_stream); -gpg_error_t http_open_document (http_t *r_hd, +gpg_error_t http_open_document (ctrl_t ctrl, http_t *r_hd, const char *document, const char *auth, unsigned int flags, diff --git a/dirmngr/ks-engine-finger.c b/dirmngr/ks-engine-finger.c index e53a0ee..30ede15 100644 --- a/dirmngr/ks-engine-finger.c +++ b/dirmngr/ks-engine-finger.c @@ -82,7 +82,7 @@ ks_finger_fetch (ctrl_t ctrl, parsed_uri_t uri, estream_t *r_fp) } *server++ = 0; - err = http_raw_connect (&http, server, 79, + err = http_raw_connect (ctrl, &http, server, 79, ((dirmngr_use_tor ()? HTTP_FLAG_FORCE_TOR : 0) | (opt.disable_ipv4? HTTP_FLAG_IGNORE_IPv4 : 0) | (opt.disable_ipv6? HTTP_FLAG_IGNORE_IPv6 : 0)), diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c index 32840e6..6303099 100644 --- a/dirmngr/ks-engine-hkp.c +++ b/dirmngr/ks-engine-hkp.c @@ -304,7 +304,7 @@ tor_not_running_p (ctrl_t ctrl) PROTOCOL. If NAME specifies a pool (as indicated by IS_POOL), update the given reference table accordingly. */ static void -add_host (const char *name, int is_pool, +add_host (ctrl_t ctrl, const char *name, int is_pool, const dns_addrinfo_t ai, enum ks_protocol protocol, unsigned short port) { @@ -320,7 +320,7 @@ add_host (const char *name, int is_pool, if (is_pool) { /* For a pool immediately convert the address to a string. */ - tmperr = resolve_dns_addr (ai->addr, ai->addrlen, + tmperr = resolve_dns_addr (ctrl, ai->addr, ai->addrlen, (DNS_NUMERICHOST | DNS_WITHBRACKET), &tmphost); } else if (!is_ip_address (name)) @@ -337,7 +337,7 @@ add_host (const char *name, int is_pool, { /* Do a PTR lookup on AI. If a name was not found the function * returns the numeric address (with brackets). */ - tmperr = resolve_dns_addr (ai->addr, ai->addrlen, + tmperr = resolve_dns_addr (ctrl, ai->addr, ai->addrlen, DNS_WITHBRACKET, &tmphost); } @@ -498,7 +498,7 @@ map_host (ctrl_t ctrl, const char *name, const char *srvtag, int force_reselect, unsigned int srvscount; /* Check for SRV records. */ - err = get_dns_srv (name, srvtag, NULL, &srvs, &srvscount); + err = get_dns_srv (ctrl, name, srvtag, NULL, &srvs, &srvscount); if (err) { if (gpg_err_code (err) == GPG_ERR_ECONNREFUSED) @@ -514,13 +514,13 @@ map_host (ctrl_t ctrl, const char *name, const char *srvtag, int force_reselect, for (i = 0; i < srvscount; i++) { - err = resolve_dns_name (srvs[i].target, 0, + err = resolve_dns_name (ctrl, srvs[i].target, 0, AF_UNSPEC, SOCK_STREAM, &ai, &cname); if (err) continue; dirmngr_tick (ctrl); - add_host (name, is_pool, ai, protocol, srvs[i].port); + add_host (ctrl, name, is_pool, ai, protocol, srvs[i].port); new_hosts = 1; } @@ -535,7 +535,7 @@ map_host (ctrl_t ctrl, const char *name, const char *srvtag, int force_reselect, { /* Find all A records for this entry and put them into the pool list - if any. */ - err = resolve_dns_name (name, 0, 0, SOCK_STREAM, &aibuf, &cname); + err = resolve_dns_name (ctrl, name, 0, 0, SOCK_STREAM, &aibuf, &cname); if (err) { log_error ("resolving '%s' failed: %s\n", name, gpg_strerror (err)); @@ -566,7 +566,7 @@ map_host (ctrl_t ctrl, const char *name, const char *srvtag, int force_reselect, continue; dirmngr_tick (ctrl); - add_host (name, is_pool, ai, 0, 0); + add_host (ctrl, name, is_pool, ai, 0, 0); new_hosts = 1; } @@ -624,7 +624,7 @@ map_host (ctrl_t ctrl, const char *name, const char *srvtag, int force_reselect, * hosttable. */ char *host; - err = resolve_dns_name (hi->name, 0, 0, SOCK_STREAM, &aibuf, NULL); + err = resolve_dns_name (ctrl, hi->name, 0, 0, SOCK_STREAM, &aibuf, NULL); if (!err) { for (ai = aibuf; ai; ai = ai->next) @@ -632,7 +632,8 @@ map_host (ctrl_t ctrl, const char *name, const char *srvtag, int force_reselect, if ((!opt.disable_ipv6 && ai->family == AF_INET6) || (!opt.disable_ipv4 && ai->family == AF_INET)) { - err = resolve_dns_addr (ai->addr, ai->addrlen, 0, &host); + err = resolve_dns_addr (ctrl, + ai->addr, ai->addrlen, 0, &host); if (!err) { /* Okay, we return the first found name. */ @@ -865,7 +866,7 @@ ks_hkp_print_hosttable (ctrl_t ctrl) /* Turn the numerical IP address string into an AI and * then do a DNS PTR lookup. */ - if (!resolve_dns_name (hi->name, 0, 0, + if (!resolve_dns_name (ctrl, hi->name, 0, 0, SOCK_STREAM, &aibuf, &canon)) { @@ -876,7 +877,7 @@ ks_hkp_print_hosttable (ctrl_t ctrl) } for (ai = aibuf; !canon && ai; ai = ai->next) { - resolve_dns_addr (ai->addr, ai->addrlen, + resolve_dns_addr (ctrl, ai->addr, ai->addrlen, DNS_WITHBRACKET, &canon); if (canon && is_ip_address (canon)) { @@ -896,14 +897,14 @@ ks_hkp_print_hosttable (ctrl_t ctrl) /* Get the IP address as a string from a name. Note * that resolve_dns_addr allocates CANON on success * and thus terminates the loop. */ - if (!resolve_dns_name (hi->name, 0, + if (!resolve_dns_name (ctrl, hi->name, 0, hi->v6? AF_INET6 : AF_INET, SOCK_STREAM, &aibuf, NULL)) { for (ai = aibuf; !canon && ai; ai = ai->next) { - resolve_dns_addr (ai->addr, ai->addrlen, + resolve_dns_addr (ctrl, ai->addr, ai->addrlen, DNS_NUMERICHOST|DNS_WITHBRACKET, &canon); } @@ -1182,7 +1183,7 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr, http_session_set_timeout (session, ctrl->timeout); once_more: - err = http_open (&http, + err = http_open (ctrl, &http, post_cb? HTTP_REQ_POST : HTTP_REQ_GET, request, httphost, diff --git a/dirmngr/ks-engine-http.c b/dirmngr/ks-engine-http.c index 946c927..9e6b9e1 100644 --- a/dirmngr/ks-engine-http.c +++ b/dirmngr/ks-engine-http.c @@ -103,7 +103,7 @@ ks_http_fetch (ctrl_t ctrl, const char *url, unsigned int flags, http_session_set_timeout (session, ctrl->timeout); *r_fp = NULL; - err = http_open (&http, + err = http_open (ctrl, &http, HTTP_REQ_GET, url, /* httphost */ NULL, diff --git a/dirmngr/ocsp.c b/dirmngr/ocsp.c index 22391c3..ca28960 100644 --- a/dirmngr/ocsp.c +++ b/dirmngr/ocsp.c @@ -172,7 +172,7 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md, } once_more: - err = http_open (&http, HTTP_REQ_POST, url, NULL, NULL, + err = http_open (ctrl, &http, HTTP_REQ_POST, url, NULL, NULL, ((opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0) | (dirmngr_use_tor ()? HTTP_FLAG_FORCE_TOR:0) | (opt.disable_ipv4? HTTP_FLAG_IGNORE_IPv4 : 0) diff --git a/dirmngr/server.c b/dirmngr/server.c index b7cdb24..33ce4cf 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -666,7 +666,7 @@ static const char hlp_dns_cert[] = static gpg_error_t cmd_dns_cert (assuan_context_t ctx, char *line) { - /* ctrl_t ctrl = assuan_get_pointer (ctx); */ + ctrl_t ctrl = assuan_get_pointer (ctx); gpg_error_t err = 0; int pka_mode, dane_mode; char *mbox = NULL; @@ -782,7 +782,7 @@ cmd_dns_cert (assuan_context_t ctx, char *line) else name = line; - err = get_dns_cert (name, certtype, &key, &keylen, &fpr, &fprlen, &url); + err = get_dns_cert (ctrl, name, certtype, &key, &keylen, &fpr, &fprlen, &url); if (err) goto leave; @@ -883,7 +883,7 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line) size_t domainlen, targetlen; int i; - err = get_dns_srv (domain, "openpgpkey", NULL, &srvs, &srvscount); + err = get_dns_srv (ctrl, domain, "openpgpkey", NULL, &srvs, &srvscount); if (err) goto leave; @@ -2977,7 +2977,7 @@ dirmngr_status_printf (ctrl_t ctrl, const char *keyword, va_list arg_ptr; assuan_context_t ctx; - if (!ctrl->server_local || !(ctx = ctrl->server_local->assuan_ctx)) + if (!ctrl || !ctrl->server_local || !(ctx = ctrl->server_local->assuan_ctx)) return 0; va_start (arg_ptr, format); diff --git a/dirmngr/t-dns-stuff.c b/dirmngr/t-dns-stuff.c index 5a3ede1..6d52160 100644 --- a/dirmngr/t-dns-stuff.c +++ b/dirmngr/t-dns-stuff.c @@ -178,7 +178,7 @@ main (int argc, char **argv) if (verbose || any_options) printf ("CERT lookup on '%s'\n", name); - err = get_dns_cert (name, DNS_CERTTYPE_ANY, &key, &keylen, + err = get_dns_cert (NULL, name, DNS_CERTTYPE_ANY, &key, &keylen, &fpr, &fpr_len, &url); if (err) printf ("get_dns_cert failed: %s <%s>\n", @@ -218,7 +218,7 @@ main (int argc, char **argv) char *cname; printf ("CNAME lookup on '%s'\n", name); - err = get_dns_cname (name, &cname); + err = get_dns_cname (NULL, name, &cname); if (err) printf ("get_dns_cname failed: %s <%s>\n", gpg_strerror (err), gpg_strsource (err)); @@ -234,7 +234,7 @@ main (int argc, char **argv) unsigned int count; int i; - err = get_dns_srv (name? name : "_hkp._tcp.wwwkeys.pgp.net", + err = get_dns_srv (NULL, name? name : "_hkp._tcp.wwwkeys.pgp.net", NULL, NULL, &srv, &count); if (err) printf ("get_dns_srv failed: %s <%s>\n", @@ -261,7 +261,7 @@ main (int argc, char **argv) printf ("Lookup on '%s'\n", name); - err = resolve_dns_name (name, 0, 0, SOCK_STREAM, &aibuf, &cname); + err = resolve_dns_name (NULL, name, 0, 0, SOCK_STREAM, &aibuf, &cname); if (err) { fprintf (stderr, PGM": resolving '%s' failed: %s\n", @@ -278,7 +278,7 @@ main (int argc, char **argv) ai->family == AF_INET? "inet4" : "? ", ai->socktype, ai->protocol); - err = resolve_dns_addr (ai->addr, ai->addrlen, + err = resolve_dns_addr (NULL, ai->addr, ai->addrlen, (DNS_NUMERICHOST | (opt_bracket? DNS_WITHBRACKET:0)), &host); @@ -290,7 +290,7 @@ main (int argc, char **argv) xfree (host); } - err = resolve_dns_addr (ai->addr, ai->addrlen, + err = resolve_dns_addr (NULL, ai->addr, ai->addrlen, (opt_bracket? DNS_WITHBRACKET:0), &host); if (err) diff --git a/dirmngr/t-http.c b/dirmngr/t-http.c index 440633d..2fc0a46 100644 --- a/dirmngr/t-http.c +++ b/dirmngr/t-http.c @@ -438,7 +438,7 @@ main (int argc, char **argv) if (session) http_session_set_timeout (session, timeout); - rc = http_open_document (&hd, *argv, NULL, my_http_flags, + rc = http_open_document (NULL, &hd, *argv, NULL, my_http_flags, NULL, session, NULL, NULL); if (rc) { diff --git a/dirmngr/t-support.c b/dirmngr/t-support.c new file mode 100644 index 0000000..fc9546a --- /dev/null +++ b/dirmngr/t-support.c @@ -0,0 +1,43 @@ +/* t-support.c - Module test support (stubs etc). + * Copyright (C) 2018 g10 Code GmbH + * + * 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 . + * SPDX-License-Identifier: GPL-3.0+ + */ + +#include +#include +#include +#include + + +#include "../common/util.h" +#include "dirmngr-status.h" +#include "t-support.h" + + + +/* Stub for testing. See server.c for the real implementation. */ +gpg_error_t +dirmngr_status_printf (ctrl_t ctrl, const char *keyword, + const char *format, ...) +{ + (void)ctrl; + (void)keyword; + (void)format; + + return 0; +} diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c index 9bc90fb..d77b90d 100644 --- a/g10/call-dirmngr.c +++ b/g10/call-dirmngr.c @@ -406,6 +406,8 @@ ks_status_cb (void *opaque, const char *line) warn = _("Tor is not running"); else if ((s2 = has_leading_keyword (s, "tor_config_problem"))) warn = _("Tor is not properly configured"); + else if ((s2 = has_leading_keyword (s, "dns_config_problem"))) + warn = _("DNS is not properly configured"); else warn = NULL; ----------------------------------------------------------------------- Summary of changes: dirmngr/Makefile.am | 4 +- dirmngr/dirmngr-status.h | 39 ++++++++++++++++ dirmngr/dirmngr.h | 8 +--- dirmngr/dns-stuff.c | 78 ++++++++++++++++++------------- dirmngr/dns-stuff.h | 14 ++++-- dirmngr/http.c | 36 ++++++++------ dirmngr/http.h | 6 +-- dirmngr/ks-engine-finger.c | 2 +- dirmngr/ks-engine-hkp.c | 31 ++++++------ dirmngr/ks-engine-http.c | 2 +- dirmngr/ocsp.c | 2 +- dirmngr/server.c | 8 ++-- dirmngr/t-dns-stuff.c | 12 ++--- dirmngr/t-http.c | 2 +- g13/be-truecrypt.c => dirmngr/t-support.c | 28 ++++++----- g10/call-dirmngr.c | 2 + 16 files changed, 170 insertions(+), 104 deletions(-) create mode 100644 dirmngr/dirmngr-status.h copy g13/be-truecrypt.c => dirmngr/t-support.c (62%) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Thu Jul 26 04:45:40 2018 From: cvs at cvs.gnupg.org (by Jiří Keresteš) Date: Thu, 26 Jul 2018 04:45:40 +0200 Subject: [git] GnuPG - branch, master, updated. gnupg-2.2.7-183-g967d364 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via 967d3649d24aba623133808e8d01675dff389fbb (commit) via 1111251945aa8d0f6573f7bfc2da1600cb2bb450 (commit) from bd4048c533165fd82340354d7229fcc2220db5a5 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 967d3649d24aba623133808e8d01675dff389fbb Author: Ji?? Kereste? Date: Tue Jul 17 17:11:42 2018 +0200 scd: Add support for Trustica Cryptoucan. diff --git a/scd/apdu.c b/scd/apdu.c index 66a16f8..ce7f41f 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -965,7 +965,8 @@ pcsc_vendor_specific_init (int slot) else if (strstr (reader_table[slot].rdrname, "cyberJack") || strstr (reader_table[slot].rdrname, "DIGIPASS") || strstr (reader_table[slot].rdrname, "Gnuk") - || strstr (reader_table[slot].rdrname, "KAAN")) + || strstr (reader_table[slot].rdrname, "KAAN") + || strstr (reader_table[slot].rdrname, "Trustica")) reader_table[slot].pinpad_varlen_supported = 1; } @@ -1039,7 +1040,8 @@ pcsc_vendor_specific_init (int slot) else if (vendor == 0x0c4b /* Tested with Reiner cyberJack GO */ || vendor == 0x1a44 /* Tested with Vasco DIGIPASS 920 */ || vendor == 0x234b /* Tested with FSIJ Gnuk Token */ - || vendor == 0x0d46 /* Tested with KAAN Advanced??? */) + || vendor == 0x0d46 /* Tested with KAAN Advanced??? */ + || (vendor == 0x1fc9 && product == 0x81e6) /* Tested with Trustica Cryptoucan */) reader_table[slot].pinpad_varlen_supported = 1; return 0; diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index f33a36c..ae40f01 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -3387,6 +3387,12 @@ ccid_transceive_secure (ccid_driver_t handle, if (handle->id_product != CHERRY_ST2000) cherry_mode = 1; break; + case VENDOR_NXP: + if (handle->id_product == CRYPTOUCAN){ + pininfo->maxlen = 25; + enable_varlen = 1; + } + break; default: if ((handle->id_vendor == VENDOR_GEMPC && handle->id_product == GEMPC_PINPAD) diff --git a/scd/ccid-driver.h b/scd/ccid-driver.h index b6da30c..c31c25f 100644 --- a/scd/ccid-driver.h +++ b/scd/ccid-driver.h @@ -68,7 +68,8 @@ enum { VENDOR_REINER = 0x0c4b, VENDOR_KAAN = 0x0d46, VENDOR_FSIJ = 0x234b, - VENDOR_VASCO = 0x1a44 + VENDOR_VASCO = 0x1a44, + VENDOR_NXP = 0x1fc9, }; @@ -84,6 +85,7 @@ enum { #define GEMPC_CT30 0x3437 #define VEGA_ALPHA 0x0008 #define CYBERJACK_GO 0x0504 +#define CRYPTOUCAN 0x81e6 #endif /*CCID_DRIVER_INCLUDE_USB_IDS*/ commit 1111251945aa8d0f6573f7bfc2da1600cb2bb450 Author: NIIBE Yutaka Date: Thu Jul 26 11:44:10 2018 +0900 Register DCO for Jiri Kerestes. -- diff --git a/AUTHORS b/AUTHORS index 2251cf6..d5d7814 100644 --- a/AUTHORS +++ b/AUTHORS @@ -193,6 +193,9 @@ Ineiev James Bottomley 2018-02-01:1517501629.3145.9.camel at HansenPartnership.com: +Jiri Kerestes +2018-07-25:: + Jonas Borgstr?m 2013-08-29:521F1E7A.5080602 at borgstrom.se: ----------------------------------------------------------------------- Summary of changes: AUTHORS | 3 +++ scd/apdu.c | 6 ++++-- scd/ccid-driver.c | 6 ++++++ scd/ccid-driver.h | 4 +++- 4 files changed, 16 insertions(+), 3 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Fri Jul 27 11:23:50 2018 From: cvs at cvs.gnupg.org (by Maximilian Krambach) Date: Fri, 27 Jul 2018 11:23:50 +0200 Subject: [git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-80-gb18b96f Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, javascript-binding has been updated via b18b96fb364711025d1e5fa9f135ee682dd0558a (commit) from 4b343c4e339862a5faf8dd20590a3c4592fb6abb (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit b18b96fb364711025d1e5fa9f135ee682dd0558a Author: Maximilian Krambach Date: Fri Jul 27 11:20:33 2018 +0200 js: clean up test extension -- Tests will now run with one instance of gpgmejs each block, which reduces overhead. Readability is (hopefully) improved), some negative tests are added. There is still a performance problem in base64 encoding/decoding, which causes some tests to fail due to time out. diff --git a/lang/js/BrowserTestExtension/tests/KeyImportExport.js b/lang/js/BrowserTestExtension/tests/KeyImportExport.js index ed307b3..d2fa2d3 100644 --- a/lang/js/BrowserTestExtension/tests/KeyImportExport.js +++ b/lang/js/BrowserTestExtension/tests/KeyImportExport.js @@ -22,18 +22,25 @@ * Raimund Renkert */ -/* global describe, it, expect, Gpgmejs, ImportablePublicKey, inputvalues */ +/* global describe, it, expect, before, afterEach, Gpgmejs*/ +/* global ImportablePublicKey, inputvalues */ describe('Key importing', function () { - it('Prepare test Key (deleting it from gnupg, if present)', function(done){ - let prm = Gpgmejs.init(); - prm.then(function (context) { - expect(context.Keyring.getKeys).to.be.a('function'); - context.Keyring.getKeys(ImportablePublicKey.fingerprint).then( + const fpr = ImportablePublicKey.fingerprint; + const pubKey = ImportablePublicKey.key; + const changedKey = ImportablePublicKey.keyChangedUserId; + + let context = null; + before(function(done){ + const prm = Gpgmejs.init(); + prm.then(function(gpgmejs){ + context = gpgmejs; + context.Keyring.getKeys(fpr).then( function(result){ if (result.length === 1) { - result[0].delete().then(function(result){ - expect(result).to.be.true; + result[0].delete().then(function(){ + done(); + },function(){ done(); }); } else { @@ -43,76 +50,79 @@ describe('Key importing', function () { }); }); - it('importing, updating, then deleting public Key', function (done) { - //This test runs in one large step, to ensure the proper state of the - // key in all stages. - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.Keyring.getKeys(ImportablePublicKey.fingerprint).then( - function(result){ - expect(result).to.be.an('array'); - expect(result.length).to.equal(0); - context.Keyring.importKey(ImportablePublicKey.key, true) - .then(function(result){ - expect(result.Keys[0]).to.not.be.undefined; - expect(result.Keys[0].key).to.be.an('object'); - expect(result.Keys[0].key.fingerprint).to.equal( - ImportablePublicKey.fingerprint); - expect(result.Keys[0].status).to.equal('newkey'); - context.Keyring.importKey( - ImportablePublicKey.keyChangedUserId,true) - .then(function(res){ - expect(res.Keys[0]).to.not.be.undefined; - expect(res.Keys[0].key).to.be.an('object'); - expect(res.Keys[0].key.fingerprint).to.equal( - ImportablePublicKey.fingerprint); - expect(res.Keys[0].status).to.equal( - 'change'); - expect( - res.Keys[0].changes.userId).to.be.true; - expect( - res.Keys[0].changes.subkey).to.be.false; - expect( - res.Keys[0].changes.signature).to.be.true; - res.Keys[0].key.delete().then(function(result){ - expect(result).to.be.true; - done(); - }); - }); - }); + afterEach(function(done){ + // delete the test key if still present + context.Keyring.getKeys(fpr).then( + function(result){ + if (result.length === 1) { + result[0].delete().then(function(){ + done(); + },function(){ + done(); + }); + } else { + done(); + } + }); + }); + + it('Importing Key', function (done) { + context.Keyring.getKeys(fpr).then(function(result){ + expect(result).to.be.an('array'); + expect(result.length).to.equal(0); + context.Keyring.importKey(pubKey).then(function(result){ + expect(result[0]).to.not.be.undefined; + expect(result[0].key).to.be.an('object'); + expect(result[0].key.fingerprint).to.equal(fpr); + expect(result[0].status).to.equal('newkey'); + done(); + }); + }); + }); + + it('Updating Key', function(done){ + context.Keyring.importKey(pubKey) + .then(function(result){ + expect(result[0].key).to.not.be.undefined; + expect(result[0].status).to.equal('newkey'); + context.Keyring.importKey(changedKey).then(function(res){ + expect(res[0].key).to.be.an('object'); + expect(res[0].key.fingerprint).to.equal(fpr); + expect(res[0].status).to.equal('change'); + expect(res[0].changes.userId).to.be.true; + expect(res[0].changes.subkey).to.be.false; + expect(res[0].changes.signature).to.be.true; + done(); }); + }); + }); + + it('Deleting Key', function(done) { + context.Keyring.importKey(pubKey).then(function(result){ + expect(result[0].key).to.be.an('object'); + expect(result[0].key.fingerprint).to.equal(fpr); + result[0].key.delete().then(function(result){ + expect(result).to.be.true; + done(); + }); }); }); it('Import result feedback', function(done){ - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.Keyring.getKeys(ImportablePublicKey.fingerprint).then( - function(result){ - expect(result).to.be.an('array'); - expect(result.length).to.equal(0); - context.Keyring.importKey(ImportablePublicKey.key, true) - .then(function(result){ - expect(result).to.be.an('object'); - expect(result.Keys[0]).to.be.an('object'); - expect(result.Keys[0].key.fingerprint).to.equal( - ImportablePublicKey.fingerprint); - expect(result.Keys[0].status).to.equal('newkey'); - result.Keys[0].key.getArmor().then(function(armor){ - expect(armor).to.be.a('string'); - result.Keys[0].key.delete().then(function(){ - done(); - }); - }); - }); - }); + context.Keyring.importKey(pubKey, true).then(function(result){ + expect(result).to.be.an('object'); + expect(result.Keys[0]).to.be.an('object'); + expect(result.Keys[0].key.fingerprint).to.equal(fpr); + expect(result.Keys[0].status).to.equal('newkey'); + result.Keys[0].key.getArmor().then(function(armor){ + expect(armor).to.be.a('string'); + done(); + }); }); }); it('exporting armored Key with getKeysArmored', function (done) { - let prm = Gpgmejs.init(); - const fpr = inputvalues.encrypt.good.fingerprint; - prm.then(function (context) { + context.Keyring.importKey(pubKey).then(function(){ context.Keyring.getKeysArmored(fpr).then(function(result){ expect(result).to.be.an('object'); expect(result.armored).to.be.a('string'); @@ -121,18 +131,15 @@ describe('Key importing', function () { }); }); }); - it('exporting armored Key (including secret fingerprints) with ' - + 'getKeysArmored', function (done) { - let prm = Gpgmejs.init(); - const fpr = inputvalues.encrypt.good.fingerprint; - prm.then(function (context) { - context.Keyring.getKeysArmored(fpr, true).then(function(result){ - expect(result).to.be.an('object'); - expect(result.armored).to.be.a('string'); - expect(result.secret_fprs).to.be.an('array'); - expect(result.secret_fprs[0]).to.equal(fpr); - done(); - }); + + it('Exporting Key (including secret fingerprints)', function (done) { + const key_secret = inputvalues.encrypt.good.fingerprint; + context.Keyring.getKeysArmored(key_secret, true).then(function(result){ + expect(result).to.be.an('object'); + expect(result.armored).to.be.a('string'); + expect(result.secret_fprs).to.be.an('array'); + expect(result.secret_fprs[0]).to.equal(key_secret); + done(); }); }); }); \ No newline at end of file diff --git a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js index bd72c1d..80b293d 100644 --- a/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptDecryptTest.js @@ -21,152 +21,101 @@ * Maximilian Krambach */ -/* global describe, it, expect, Gpgmejs */ +/* global describe, it, expect, before, Gpgmejs */ /* global inputvalues, encryptedData, bigString, bigBoringString */ describe('Encryption and Decryption', function () { + let context = null; + let good_fpr = inputvalues.encrypt.good.fingerprint; + + before(function(done){ + const prm = Gpgmejs.init(); + prm.then(function(gpgmejs){ + context = gpgmejs; + done(); + }); + }); + it('Successful encrypt and decrypt simple string', function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.encrypt( - inputvalues.encrypt.good.data, - inputvalues.encrypt.good.fingerprint).then( - function (answer) { - expect(answer).to.not.be.empty; - expect(answer.data).to.be.a('string'); - expect(answer.data).to.include('BEGIN PGP MESSAGE'); - expect(answer.data).to.include('END PGP MESSAGE'); - context.decrypt(answer.data).then(function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal( - inputvalues.encrypt.good.data); - done(); - }); - }); + let data = inputvalues.encrypt.good.data; + context.encrypt(data, good_fpr).then(function (answer) { + expect(answer).to.not.be.empty; + expect(answer.data).to.be.a('string'); + expect(answer.data).to.include('BEGIN PGP MESSAGE'); + expect(answer.data).to.include('END PGP MESSAGE'); + + context.decrypt(answer.data).then(function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal( + inputvalues.encrypt.good.data); + done(); + }); }); }); it('Decrypt simple non-ascii', function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - let data = encryptedData; - context.decrypt(data).then( - function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal( - '??u?erste ?? f?r ?oquis at h?me! ?????? ????\n'); - done(); - }); + let data = encryptedData; + context.decrypt(data).then(function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal( + '??u?erste ?? f?r ?oquis at h?me! ?????? ????\n'); + done(); }); }).timeout(3000); - it('Roundtrip does not destroy trailing whitespace', - function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - let data = 'Keks. \rKeks \n Keks \r\n'; - context.encrypt(data, - inputvalues.encrypt.good.fingerprint).then( - function (answer) { - expect(answer).to.not.be.empty; - expect(answer.data).to.be.a('string'); - expect(answer.data).to.include( - 'BEGIN PGP MESSAGE'); - expect(answer.data).to.include( - 'END PGP MESSAGE'); - context.decrypt(answer.data).then( - function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal(data); - done(); - - }); - }); - }); - }).timeout(5000); + it('Trailing whitespace and different line endings', function (done) { + const data = 'Keks. \rKeks \n Keks \r\n'; + context.encrypt(data, good_fpr).then(function (answer) { + expect(answer).to.not.be.empty; + expect(answer.data).to.be.a('string'); + expect(answer.data).to.include('BEGIN PGP MESSAGE'); + expect(answer.data).to.include('END PGP MESSAGE'); - for (let j = 0; j < inputvalues.encrypt.good.data_nonascii_32.length; j++){ - it('Roundtrip with >1MB non-ascii input meeting default chunksize (' + - (j + 1) + '/' - + inputvalues.encrypt.good.data_nonascii_32.length + ')', - function (done) { - let input = inputvalues.encrypt.good.data_nonascii_32[j]; - expect(input).to.have.length(32); - let prm = Gpgmejs.init(); - prm.then(function (context) { - let data = ''; - for (let i=0; i < 34 * 1024; i++){ - data += input; - } - context.encrypt(data, - inputvalues.encrypt.good.fingerprint).then( - function (answer) { - expect(answer).to.not.be.empty; - expect(answer.data).to.be.a('string'); - expect(answer.data).to.include( - 'BEGIN PGP MESSAGE'); - expect(answer.data).to.include( - 'END PGP MESSAGE'); - context.decrypt(answer.data).then( - function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal(data); - done(); - }); - }); + context.decrypt(answer.data).then(function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(data); + done(); }); - }).timeout(3000); - } + }); + }).timeout(5000); it('Random data, as string', function (done) { let data = bigString(1000); - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.encrypt(data, - inputvalues.encrypt.good.fingerprint).then( - function (answer) { - expect(answer).to.not.be.empty; - expect(answer.data).to.be.a('string'); - expect(answer.data).to.include( - 'BEGIN PGP MESSAGE'); - expect(answer.data).to.include( - 'END PGP MESSAGE'); - context.decrypt(answer.data).then( - function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal(data); - done(); - }); - }); + context.encrypt(data, good_fpr).then(function (answer) { + expect(answer).to.not.be.empty; + expect(answer.data).to.be.a('string'); + expect(answer.data).to.include( + 'BEGIN PGP MESSAGE'); + expect(answer.data).to.include( + 'END PGP MESSAGE'); + context.decrypt(answer.data).then(function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(data); + done(); + }); }); }).timeout(3000); it('Data, input as base64', function (done) { let data = inputvalues.encrypt.good.data; let b64data = btoa(data); - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.encrypt(b64data, - inputvalues.encrypt.good.fingerprint, true).then( - function (answer) { - expect(answer).to.not.be.empty; - expect(answer.data).to.be.a('string'); - expect(answer.data).to.include( - 'BEGIN PGP MESSAGE'); - expect(answer.data).to.include( - 'END PGP MESSAGE'); - context.decrypt(answer.data).then( - function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(data).to.equal(data); - done(); - }); + context.encrypt(b64data, good_fpr, true).then(function (answer) { + expect(answer).to.not.be.empty; + expect(answer.data).to.be.a('string'); + expect(answer.data).to.include( + 'BEGIN PGP MESSAGE'); + expect(answer.data).to.include( + 'END PGP MESSAGE'); + context.decrypt(answer.data).then( + function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(data).to.equal(data); + done(); }); }); }).timeout(3000); @@ -174,26 +123,48 @@ describe('Encryption and Decryption', function () { it('Random data, input as base64', function (done) { let data = bigBoringString(0.001); let b64data = btoa(data); - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.encrypt(b64data, - inputvalues.encrypt.good.fingerprint, true).then( - function (answer) { - expect(answer).to.not.be.empty; - expect(answer.data).to.be.a('string'); - expect(answer.data).to.include( - 'BEGIN PGP MESSAGE'); - expect(answer.data).to.include( - 'END PGP MESSAGE'); - context.decrypt(answer.data).then( - function (result) { - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - expect(result.data).to.equal(b64data); - done(); - }); + context.encrypt(b64data, good_fpr, true).then(function (answer) { + expect(answer).to.not.be.empty; + expect(answer.data).to.be.a('string'); + expect(answer.data).to.include( + 'BEGIN PGP MESSAGE'); + expect(answer.data).to.include( + 'END PGP MESSAGE'); + context.decrypt(answer.data).then( + function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(b64data); + done(); }); }); }).timeout(3000); + for (let j = 0; j < inputvalues.encrypt.good.data_nonascii_32.length; j++){ + it('Roundtrip with >1MB non-ascii input meeting default chunksize (' + + (j + 1) + '/' + + inputvalues.encrypt.good.data_nonascii_32.length + ')', + function (done) { + let input = inputvalues.encrypt.good.data_nonascii_32[j]; + expect(input).to.have.length(32); + let data = ''; + for (let i=0; i < 34 * 1024; i++){ + data += input; + } + context.encrypt(data,good_fpr).then(function (answer) { + expect(answer).to.not.be.empty; + expect(answer.data).to.be.a('string'); + expect(answer.data).to.include( + 'BEGIN PGP MESSAGE'); + expect(answer.data).to.include( + 'END PGP MESSAGE'); + context.decrypt(answer.data).then(function (result) { + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(data); + done(); + }); + }); + }).timeout(5000); + } }); diff --git a/lang/js/BrowserTestExtension/tests/encryptTest.js b/lang/js/BrowserTestExtension/tests/encryptTest.js index 1114125..3ead815 100644 --- a/lang/js/BrowserTestExtension/tests/encryptTest.js +++ b/lang/js/BrowserTestExtension/tests/encryptTest.js @@ -21,134 +21,91 @@ * Maximilian Krambach */ -/* global describe, it, expect, Gpgmejs */ +/* global describe, it, expect, before, Gpgmejs */ /* global inputvalues, fixedLengthString */ describe('Encryption', function () { - it('Successful encrypt', function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.encrypt( - inputvalues.encrypt.good.data, - inputvalues.encrypt.good.fingerprint).then(function (answer) { - expect(answer).to.not.be.empty; - expect(answer.data).to.be.a('string'); - expect(answer.data).to.include('BEGIN PGP MESSAGE'); - expect(answer.data).to.include('END PGP MESSAGE'); - done(); - }); + let context = null; + const good_fpr = inputvalues.encrypt.good.fingerprint; + before(function(done){ + const prm = Gpgmejs.init(); + prm.then(function(gpgmejs){ + context = gpgmejs; + done(); }); }); - it('Successful encrypt 5 MB', function (done) { - let prm = Gpgmejs.init(); - let data = fixedLengthString(5); - prm.then(function (context) { - context.encrypt( - data, - inputvalues.encrypt.good.fingerprint).then(function (answer) { - expect(answer).to.not.be.empty; - expect(answer.data).to.be.a('string'); - expect(answer.data).to.include('BEGIN PGP MESSAGE'); - expect(answer.data).to.include('END PGP MESSAGE'); - done(); - }); - }); - }).timeout(10000); - - it('Successful encrypt 20 MB', function (done) { - let prm = Gpgmejs.init(); - let data = fixedLengthString(20); - prm.then(function (context) { - context.encrypt( - data, - inputvalues.encrypt.good.fingerprint).then(function (answer) { - expect(answer).to.not.be.empty; - expect(answer.data).to.be.a('string'); - expect(answer.data).to.include('BEGIN PGP MESSAGE'); - expect(answer.data).to.include('END PGP MESSAGE'); - done(); - }); + it('Successful encrypt', function (done) { + const data = inputvalues.encrypt.good.data; + context.encrypt(data, good_fpr).then(function (answer) { + expect(answer).to.not.be.empty; + expect(answer.data).to.be.a('string'); + expect(answer.data).to.include('BEGIN PGP MESSAGE'); + expect(answer.data).to.include('END PGP MESSAGE'); + done(); }); - }).timeout(20000); + }); - it('Successful encrypt 50 MB', function (done) { - let prm = Gpgmejs.init(); - let data = fixedLengthString(50); - prm.then(function (context) { - context.encrypt( - data, - inputvalues.encrypt.good.fingerprint).then(function (answer) { + const sizes = [5,20,50]; + for (let i=0; i < sizes.length; i++) { + it('Successful encrypt a ' + sizes[i] + 'MB message', function (done) { + const data = fixedLengthString(sizes[i]); + context.encrypt(data, good_fpr).then(function (answer) { expect(answer).to.not.be.empty; expect(answer.data).to.be.a('string'); expect(answer.data).to.include('BEGIN PGP MESSAGE'); expect(answer.data).to.include('END PGP MESSAGE'); done(); }); - }); - }).timeout(20000); + }).timeout(20000); + } it('Sending encryption without keys fails', function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.encrypt( - inputvalues.encrypt.good.data, - null).then(function (answer) { - expect(answer).to.be.undefined; - }, function(error){ - expect(error).to.be.an('Error'); - expect(error.code).to.equal('MSG_INCOMPLETE'); - done(); - }); + const data = inputvalues.encrypt.good.data; + context.encrypt(data,null).then(function (answer) { + expect(answer).to.be.undefined; + }, function(error){ + expect(error).to.be.an('Error'); + expect(error.code).to.equal('MSG_INCOMPLETE'); + done(); }); }); it('Sending encryption without data fails', function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.encrypt( - null, inputvalues.encrypt.good.keyid).then(function (answer) { - expect(answer).to.be.undefined; - }, function (error) { - expect(error).to.be.an.instanceof(Error); - expect(error.code).to.equal('MSG_INCOMPLETE'); - done(); - }); + context.encrypt(null, good_fpr).then(function (answer) { + expect(answer).to.be.undefined; + }, function (error) { + expect(error).to.be.an.instanceof(Error); + expect(error.code).to.equal('MSG_INCOMPLETE'); + done(); }); }); it('Sending encryption with non existing keys fails', function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.encrypt( - inputvalues.encrypt.good.data, - inputvalues.encrypt.bad.fingerprint).then(function (answer) { - expect(answer).to.be.undefined; - }, function(error){ - expect(error).to.be.an('Error'); - expect(error.code).to.not.be.undefined; - expect(error.code).to.equal('GNUPG_ERROR'); - done(); - }); + const data = inputvalues.encrypt.good.data; + const bad_fpr = inputvalues.encrypt.bad.fingerprint; + context.encrypt(data, bad_fpr).then(function (answer) { + expect(answer).to.be.undefined; + }, function(error){ + expect(error).to.be.an('Error'); + expect(error.code).to.not.be.undefined; + expect(error.code).to.equal('GNUPG_ERROR'); + done(); }); }).timeout(5000); it('Overly large message ( > 64MB) is rejected', function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.encrypt( - fixedLengthString(65), - inputvalues.encrypt.good.fingerprint).then(function (answer) { - expect(answer).to.be.undefined; - }, function(error){ - expect(error).to.be.an.instanceof(Error); - // TODO: there is a 64 MB hard limit at least in chrome at: - // chromium//extensions/renderer/messaging_util.cc: - // kMaxMessageLength - // The error will be a browser error, not from gnupg or from - // this library - done(); - }); + const data = fixedLengthString(65); + context.encrypt(data, good_fpr).then(function (answer) { + expect(answer).to.be.undefined; + }, function(error){ + expect(error).to.be.an.instanceof(Error); + // TODO: there is a 64 MB hard limit at least in chrome at: + // chromium//extensions/renderer/messaging_util.cc: + // kMaxMessageLength + // The error will be a browser error, not from gnupg or from + // this library + done(); }); }).timeout(8000); diff --git a/lang/js/BrowserTestExtension/tests/inputvalues.js b/lang/js/BrowserTestExtension/tests/inputvalues.js index 1c70190..5289eab 100644 --- a/lang/js/BrowserTestExtension/tests/inputvalues.js +++ b/lang/js/BrowserTestExtension/tests/inputvalues.js @@ -53,6 +53,39 @@ const inputvalues = {// eslint-disable-line no-unused-vars // bogus fingerprint) fingerprint: 'CDC3A2B2860625CCBFC5AAAAAC6D1B604967FC4A' } + }, + + signedMessage: { + good: '-----BEGIN PGP SIGNED MESSAGE-----\n' + + 'Hash: SHA256\n' + + '\n' + + 'Matschige M?nsteraner Marshmallows\n' + + '-----BEGIN PGP SIGNATURE-----\n' + + '\n' + + 'iQEzBAEBCAAdFiEE1Bc1uRI2/biCBIxaIwFjXu/wywUFAltRoiMACgkQIwFjXu/w\n' + + 'ywUvagf6ApQbZbTPOROqfTfxAPdtzJsSDKHla6D0G5wom2gJbAVb0B2YS1c3Gjpq\n' + + 'I4kTKT1W1RRkne0mK9cexf4sjb5DQcV8PLhfmmAJEpljDFei6i/E309BvW4CZ4rG\n' + + 'jiurf8CkaNkrwn2fXJDaT4taVCX3V5FQAlgLxgOrm1zjiGA4mz98gi5zL4hvZXF9\n' + + 'dHY0jLwtQMVUO99q+5XC1TJfPsnteWL9m4e/YYPfYJMZZso+/0ib/yX5vHCk7RXH\n' + + 'CfhY40nMXSYdfl8mDOhvnKcCvy8qxetFv9uCX06OqepAamu/bvxslrzocRyJ/eq0\n' + + 'T2JfzEN+E7Y3PB8UwLgp/ZRmG8zRrQ==\n' + + '=ioB6\n' + + '-----END PGP SIGNATURE-----\n', + bad: '-----BEGIN PGP SIGNED MESSAGE-----\n' + + 'Hash: SHA256\n' + + '\n' + + 'Matschige M?nchener Marshmallows\n' + + '-----BEGIN PGP SIGNATURE-----\n' + + '\n' + + 'iQEzBAEBCAAdFiEE1Bc1uRI2/biCBIxaIwFjXu/wywUFAltRoiMACgkQIwFjXu/w\n' + + 'ywUvagf6ApQbZbTPOROqfTfxAPdtzJsSDKHla6D0G5wom2gJbAVb0B2YS1c3Gjpq\n' + + 'I4kTKT1W1RRkne0mK9cexf4sjb5DQcV8PLhfmmAJEpljDFei6i/E309BvW4CZ4rG\n' + + 'jiurf8CkaNkrwn2fXJDaT4taVCX3V5FQAlgLxgOrm1zjiGA4mz98gi5zL4hvZXF9\n' + + 'dHY0jLwtQMVUO99q+5XC1TJfPsnteWL9m4e/YYPfYJMZZso+/0ib/yX5vHCk7RXH\n' + + 'CfhY40nMXSYdfl8mDOhvnKcCvy8qxetFv9uCX06OqepAamu/bvxslrzocRyJ/eq0\n' + + 'T2JfzEN+E7Y3PB8UwLgp/ZRmG8zRrQ==\n' + + '=ioB6\n' + + '-----END PGP SIGNATURE-----\n', } }; @@ -83,7 +116,7 @@ function bigUint8(megabytes){// eslint-disable-line no-unused-vars let maxlength = 1024 * 1024 * megabytes; let uint = new Uint8Array(maxlength); for (let i= 0; i < maxlength; i++){ - uint[i] = Math.random() * Math.floor(256); + uint[i] = Math.floor(Math.random() * 256); } return uint; } @@ -125,6 +158,27 @@ function slightlyLessBoringString(megabytes, set){ return string.join(''); } +// Take a gpg looking string and destroy it a bit by changing random values +// eslint-disable-next-line no-unused-vars +function destroylegitimateGpg(string, mutations=5){ + const allowed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/\n'; + for (let i=0; i < mutations.length; i++){ + // leave the first and last 35 chars (header/footer) intact + let position = Math.floor(Math.random() *(string.length - 70)) + 35; + let str0 = string.substring(0,position - 1); + let str1 = string.substring(position, position + 1); + let str2 = string.substring(position +1); + let success = false; + while (!success){ + let newchar = Math.floor(Math.random() * allowed.length); + if (newchar !== str1){ + string = str0 + newchar + str2; + success = true; + } + } + } +} + // Data encrypted with testKey const encryptedData =// eslint-disable-line no-unused-vars '-----BEGIN PGP MESSAGE-----\n' + diff --git a/lang/js/BrowserTestExtension/tests/longRunningTests.js b/lang/js/BrowserTestExtension/tests/longRunningTests.js index e148d1c..03f0390 100644 --- a/lang/js/BrowserTestExtension/tests/longRunningTests.js +++ b/lang/js/BrowserTestExtension/tests/longRunningTests.js @@ -20,61 +20,37 @@ * Author(s): * Maximilian Krambach */ -/* global describe, it, expect, Gpgmejs */ +/* global describe, it, before, expect, Gpgmejs */ /* global bigString, inputvalues */ describe('Long running Encryption/Decryption', function () { + let context = null; + const good_fpr = inputvalues.encrypt.good.fingerprint; + before(function(done){ + const prm = Gpgmejs.init(); + prm.then(function(gpgmejs){ + context = gpgmejs; + done(); + }); + }); + for (let i=0; i < 101; i++) { - it('Successful encrypt/decrypt completely random data ' + - (i+1) + '/100', function (done) { - let prm = Gpgmejs.init(); - let data = bigString(2*1024*1024); - prm.then(function (context) { - context.encrypt(data, - inputvalues.encrypt.good.fingerprint).then( - function (answer){ - expect(answer).to.not.be.empty; - expect(answer.data).to.be.a('string'); - expect(answer.data).to.include( - 'BEGIN PGP MESSAGE'); - expect(answer.data).to.include( - 'END PGP MESSAGE'); - context.decrypt(answer.data).then( - function(result){ - expect(result).to.not.be.empty; - expect(result.data).to.be.a('string'); - /* - if (result.data.length !== data.length) { - console.log('diff: ' + - (result.data.length - data.length)); - for (let i=0; i < result.data.length; i++){ - if (result.data[i] !== data[i]){ - console.log('position: ' + i); - console.log('result : ' + - result.data.charCodeAt(i) + - result.data[i-2] + - result.data[i-1] + - result.data[i] + - result.data[i+1] + - result.data[i+2]); - console.log('original: ' + - data.charCodeAt(i) + - data[i-2] + - data[i-1] + - data[i] + - data[i+1] + - data[i+2]); - break; - } - } - } - */ - expect(result.data).to.equal(data); - done(); - }); - }); + it('Successful encrypt/decrypt completely random data ' + + (i+1) + '/100', function (done) { + const data = bigString(2*1024*1024); + context.encrypt(data,good_fpr).then(function (answer){ + expect(answer).to.not.be.empty; + expect(answer.data).to.be.a('string'); + expect(answer.data).to.include('BEGIN PGP MESSAGE'); + expect(answer.data).to.include('END PGP MESSAGE'); + context.decrypt(answer.data).then(function(result){ + expect(result).to.not.be.empty; + expect(result.data).to.be.a('string'); + expect(result.data).to.equal(data); + done(); + }); }); - }).timeout(8000); + }).timeout(15000); } }); diff --git a/lang/js/BrowserTestExtension/tests/signTest.js b/lang/js/BrowserTestExtension/tests/signTest.js index ffd2d5d..2763dad 100644 --- a/lang/js/BrowserTestExtension/tests/signTest.js +++ b/lang/js/BrowserTestExtension/tests/signTest.js @@ -21,42 +21,42 @@ * Maximilian Krambach */ -/* global describe, it, expect, Gpgmejs */ +/* global describe, it, expect, before, Gpgmejs */ /* global bigString, inputvalues */ describe('Signing', function () { + let context = null; + const good_fpr = inputvalues.encrypt.good.fingerprint; + + before(function(done){ + const prm = Gpgmejs.init(); + prm.then(function(gpgmejs){ + context = gpgmejs; + done(); + }); + }); + it('Sign a message', function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - let data = bigString(100); - context.sign( - data, - inputvalues.encrypt.good.fingerprint).then(function (answer) { - expect(answer).to.not.be.empty; - expect(answer.data).to.be.a('string'); - expect(answer.data).to.include('BEGIN PGP SIGNATURE'); - expect(answer.data).to.include('END PGP SIGNATURE'); - expect(answer.data).to.include(data); - done(); - }); + const data = bigString(100); + context.sign(data, good_fpr).then(function (answer) { + expect(answer).to.not.be.empty; + expect(answer.data).to.be.a('string'); + expect(answer.data).to.include('BEGIN PGP SIGNATURE'); + expect(answer.data).to.include('END PGP SIGNATURE'); + expect(answer.data).to.include(data); + done(); }); }); + it('Detached sign a message', function (done) { - let prm = Gpgmejs.init(); - prm.then(function (context) { - let data = bigString(100); - context.sign( - data, - inputvalues.encrypt.good.fingerprint, - 'detached' - ).then(function (answer) { - expect(answer).to.not.be.empty; - expect(answer.data).to.be.a('string'); - expect(answer.data).to.include(data); - expect(answer.signature).to.be.a('string'); - expect(answer.signature).to.be.a('string'); - done(); - }); + const data = bigString(100); + context.sign(data,good_fpr, 'detached').then(function (answer) { + expect(answer).to.not.be.empty; + expect(answer.data).to.be.a('string'); + expect(answer.data).to.include(data); + expect(answer.signature).to.be.a('string'); + expect(answer.signature).to.be.a('string'); + done(); }); }); diff --git a/lang/js/BrowserTestExtension/tests/verifyTest.js b/lang/js/BrowserTestExtension/tests/verifyTest.js index e8e2c76..1617e2d 100644 --- a/lang/js/BrowserTestExtension/tests/verifyTest.js +++ b/lang/js/BrowserTestExtension/tests/verifyTest.js @@ -21,64 +21,63 @@ * Maximilian Krambach */ -/* global describe, it, expect, bigString, inputvalues, Gpgmejs */ +/* global describe, it, expect, before, bigString, inputvalues, Gpgmejs */ -let verifyData = { - signedMessage: '-----BEGIN PGP SIGNED MESSAGE-----\n' + - 'Hash: SHA256\n' + - '\n' + - 'Matschige M?nsteraner Marshmallows\n' + - '-----BEGIN PGP SIGNATURE-----\n' + - '\n' + - 'iQEzBAEBCAAdFiEE1Bc1uRI2/biCBIxaIwFjXu/wywUFAltRoiMACgkQIwFjXu/w\n' + - 'ywUvagf6ApQbZbTPOROqfTfxAPdtzJsSDKHla6D0G5wom2gJbAVb0B2YS1c3Gjpq\n' + - 'I4kTKT1W1RRkne0mK9cexf4sjb5DQcV8PLhfmmAJEpljDFei6i/E309BvW4CZ4rG\n' + - 'jiurf8CkaNkrwn2fXJDaT4taVCX3V5FQAlgLxgOrm1zjiGA4mz98gi5zL4hvZXF9\n' + - 'dHY0jLwtQMVUO99q+5XC1TJfPsnteWL9m4e/YYPfYJMZZso+/0ib/yX5vHCk7RXH\n' + - 'CfhY40nMXSYdfl8mDOhvnKcCvy8qxetFv9uCX06OqepAamu/bvxslrzocRyJ/eq0\n' + - 'T2JfzEN+E7Y3PB8UwLgp/ZRmG8zRrQ==\n' + - '=ioB6\n' + - '-----END PGP SIGNATURE-----\n' -}; -describe('Verify data', function () { + +describe('Verifying data', function () { + let context = null; + before(function(done){ + const prm = Gpgmejs.init(); + prm.then(function(gpgmejs){ + context = gpgmejs; + done(); + }); + }); it('Successful verify message', function (done) { - let message = verifyData.signedMessage; - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.verify(message).then(function(result){ - expect(result.data).to.be.a('string'); - expect(result.all_valid).to.be.true; - expect(result.count).to.equal(1); - expect(result.signatures.good).to.be.an('array'); - expect(result.signatures.good.length).to.equal(1); - expect(result.signatures.good[0].fingerprint) - .to.be.a('string'); - expect(result.signatures.good[0].valid).to.be.true; - done(); - }); + const message = inputvalues.signedMessage.good; + context.verify(message).then(function(result){ + expect(result.data).to.be.a('string'); + expect(result.all_valid).to.be.true; + expect(result.count).to.equal(1); + expect(result.signatures.good).to.be.an('array'); + expect(result.signatures.good.length).to.equal(1); + expect(result.signatures.good[0].fingerprint).to.be.a('string'); + expect(result.signatures.good[0].valid).to.be.true; + done(); + }); + }); + + it('Successfully recognize changed cleartext', function (done) { + const message = inputvalues.signedMessage.bad; + context.verify(message).then(function(result){ + expect(result.data).to.be.a('string'); + expect(result.all_valid).to.be.false; + expect(result.count).to.equal(1); + expect(result.signatures.bad).to.be.an('array'); + expect(result.signatures.bad.length).to.equal(1); + expect(result.signatures.bad[0].fingerprint).to.be.a('string'); + expect(result.signatures.bad[0].valid).to.be.false; + done(); }); }); it('Encrypt-Sign-Verify random message', function (done) { - let message = bigString(2000); + const message = bigString(2000); let fpr = inputvalues.encrypt.good.fingerprint; - let prm = Gpgmejs.init(); - prm.then(function (context) { - context.encrypt(message, fpr).then(function(message_enc){ - context.sign(message_enc.data, fpr).then(function(message_encsign){ - context.verify(message_encsign.data).then(function(result){ - expect(result.data).to.equal(message_enc.data); - expect(result.data).to.be.a('string'); - expect(result.all_valid).to.be.true; - expect(result.count).to.equal(1); - expect(result.signatures.good).to.be.an('array'); - expect(result.signatures.good.length).to.equal(1); - expect(result.signatures.good[0].fingerprint) - .to.equal(fpr); - expect(result.signatures.good[0].valid).to.be.true; - done(); - }); + context.encrypt(message, fpr).then(function(message_enc){ + context.sign(message_enc.data, fpr).then(function(message_encsign){ + context.verify(message_encsign.data).then(function(result){ + expect(result.data).to.equal(message_enc.data); + expect(result.data).to.be.a('string'); + expect(result.all_valid).to.be.true; + expect(result.count).to.equal(1); + expect(result.signatures.good).to.be.an('array'); + expect(result.signatures.good.length).to.equal(1); + expect( + result.signatures.good[0].fingerprint).to.equal(fpr); + expect(result.signatures.good[0].valid).to.be.true; + done(); }); }); }); ----------------------------------------------------------------------- Summary of changes: .../BrowserTestExtension/tests/KeyImportExport.js | 169 +++++++------- .../tests/encryptDecryptTest.js | 255 +++++++++------------ lang/js/BrowserTestExtension/tests/encryptTest.js | 157 +++++-------- lang/js/BrowserTestExtension/tests/inputvalues.js | 56 ++++- .../BrowserTestExtension/tests/longRunningTests.js | 76 +++--- lang/js/BrowserTestExtension/tests/signTest.js | 58 ++--- lang/js/BrowserTestExtension/tests/verifyTest.js | 99 ++++---- 7 files changed, 417 insertions(+), 453 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Fri Jul 27 17:58:46 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Fri, 27 Jul 2018 17:58:46 +0200 Subject: [git] GnuPG - branch, master, updated. gnupg-2.2.7-186-ge88f56f Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, master has been updated via e88f56f1937ac92f6a3b94e50b6db2649ec0be41 (commit) via ebe727ef596eefebb5eff7d03a98649ffc7ae3ee (commit) via ddee9f9409fb5a089883eab0fadef7b9b7e61e72 (commit) from 967d3649d24aba623133808e8d01675dff389fbb (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit e88f56f1937ac92f6a3b94e50b6db2649ec0be41 Author: Werner Koch Date: Fri Jul 27 17:35:00 2018 +0200 gpg: Set a limit for a WKD import of 256 KiB. * g10/call-dirmngr.c (MAX_WKD_RESULT_LENGTH): New. (gpg_dirmngr_wkd_get): Use it. -- WKD should return only a single key with just one UID. For key rollover 2 keys may be send. A total of 256 KiB seems to be a generous limit here. Signed-off-by: Werner Koch diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c index d77b90d..11663b9 100644 --- a/g10/call-dirmngr.c +++ b/g10/call-dirmngr.c @@ -41,6 +41,12 @@ #include "call-dirmngr.h" +/* Keys retrieved from the web key directory should be small. There + * is only one UID and we can expect that the number of subkeys is + * reasonable. So we set a generous limit of 256 KiB. */ +#define MAX_WKD_RESULT_LENGTH (256 * 1024) + + /* Parameter structure used to gather status info. Note that it is * also used for WKD requests. */ struct ks_status_parm_s @@ -1367,7 +1373,7 @@ gpg_dirmngr_wkd_get (ctrl_t ctrl, const char *name, int quick, goto leave; } - parm.memfp = es_fopenmem (0, "rwb"); + parm.memfp = es_fopenmem (MAX_WKD_RESULT_LENGTH, "rwb"); if (!parm.memfp) { err = gpg_error_from_syserror (); @@ -1375,6 +1381,8 @@ gpg_dirmngr_wkd_get (ctrl_t ctrl, const char *name, int quick, } err = assuan_transact (ctx, line, dns_cert_data_cb, &parm, NULL, NULL, ks_status_cb, &stparm); + if (gpg_err_code (err) == GPG_ERR_ENOSPC) + err = gpg_error (GPG_ERR_TOO_LARGE); if (err) goto leave; commit ebe727ef596eefebb5eff7d03a98649ffc7ae3ee Author: Werner Koch Date: Fri Jul 27 12:23:38 2018 +0200 dirmngr: Validate SRV records in WKD queries. * dirmngr/server.c (proc_wkd_get): Check the returned SRV record names to mitigate rogue DNS servers. -- I am not sure wether this really is very useful because the security relies on a trustworthy DNS system anyway. However, that check is easy enough to do. Signed-off-by: Werner Koch diff --git a/dirmngr/server.c b/dirmngr/server.c index 33ce4cf..2519fd6 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -887,6 +887,18 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line) if (err) goto leave; + /* Check for rogue DNS names. */ + for (i = 0; i < srvscount; i++) + { + if (!is_valid_domain_name (srvs[i].target)) + { + err = gpg_error (GPG_ERR_DNS_ADDRESS); + log_error ("rogue openpgpkey SRV record for '%s'\n", domain); + xfree (srvs); + goto leave; + } + } + /* Find the first target which also ends in DOMAIN or is equal * to DOMAIN. */ domainlen = strlen (domain); commit ddee9f9409fb5a089883eab0fadef7b9b7e61e72 Author: Werner Koch Date: Fri Jul 27 11:56:06 2018 +0200 common: New function to validate domain names. * common/mbox-util.c (is_valid_domain_name): New. * common/t-mbox-util.c (run_dns_test): New test. Signed-off-by: Werner Koch diff --git a/common/mbox-util.c b/common/mbox-util.c index c1f05b8..76255ba 100644 --- a/common/mbox-util.c +++ b/common/mbox-util.c @@ -241,3 +241,42 @@ is_valid_user_id (const char *uid) return 1; } + + +/* Returns true if STRING is a valid domain name according to the LDH + * rule. */ +int +is_valid_domain_name (const char *string) +{ + static char const ldh_chars[] = + "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-"; + const char *s; + + /* Note that we do not check the length limit of a label or the + * entire name */ + + for (s=string; *s; s++) + if (*s == '.') + { + if (string == s) + return 0; /* Dot at the start of the string. */ + /* (may also be at the end like in ".") */ + if (s[1] == '.') + return 0; /* No - double dot. */ + } + else if (!strchr (ldh_chars, *s)) + return 0; + else if (*s == '-') + { + if (string == s) + return 0; /* Leading hyphen. */ + if (s[-1] == '.') + return 0; /* Hyphen at begin of a label. */ + if (s[1] == '.') + return 0; /* Hyphen at start of a label. */ + if (!s[1]) + return 0; /* Trailing hyphen. */ + } + + return !!*string; +} diff --git a/common/mbox-util.h b/common/mbox-util.h index bce003f..7355cee 100644 --- a/common/mbox-util.h +++ b/common/mbox-util.h @@ -24,6 +24,7 @@ int is_valid_mailbox (const char *name); int is_valid_mailbox_mem (const void *buffer, size_t length); char *mailbox_from_userid (const char *userid); int is_valid_user_id (const char *uid); +int is_valid_domain_name (const char *string); #endif /*GNUPG_COMMON_MBOX_UTIL_H*/ diff --git a/common/t-mbox-util.c b/common/t-mbox-util.c index 979d4b3..fb1ac12 100644 --- a/common/t-mbox-util.c +++ b/common/t-mbox-util.c @@ -33,7 +33,7 @@ static void -run_test (void) +run_mbox_test (void) { static struct { @@ -93,13 +93,64 @@ run_test (void) } +static void +run_dns_test (void) +{ + static struct + { + const char *name; + int valid; + } testtbl[] = + { + { "", 0 }, + { ".", 0 }, + { "-", 0 }, + { "a", 1 }, + { "ab", 1 }, + { "a.b", 1 }, + { "a.b.", 1 }, + { ".a.b.", 0 }, + { ".a.b", 0 }, + { "-a.b", 0 }, + { "a-.b", 0 }, + { "a.-b", 0 }, + { "a.b-", 0 }, + { "a.b-.", 0 }, + { "a..b", 0 }, + { "ab.c", 1 }, + { "a-b.c", 1 }, + { "a-b-.c", 0 }, + { "-a-b.c", 0 }, + { "example.org", 1 }, + { "x.example.org", 1 }, + { "xy.example.org", 1 }, + { "Xy.example.org", 1 }, + { "-Xy.example.org", 0 }, + { "Xy.example-.org", 0 }, + { "foo.example.org..", 0 }, + { "foo.example.org.", 1 }, + { ".foo.example.org.", 0 }, + { "..foo.example.org.", 0 }, + { NULL, 0 } + }; + int idx; + + for (idx=0; testtbl[idx].name; idx++) + { + if (is_valid_domain_name (testtbl[idx].name) != testtbl[idx].valid) + fail (idx); + } +} + + int main (int argc, char **argv) { (void)argc; (void)argv; - run_test (); + run_mbox_test (); + run_dns_test (); return 0; } ----------------------------------------------------------------------- Summary of changes: common/mbox-util.c | 39 +++++++++++++++++++++++++++++++++++++ common/mbox-util.h | 1 + common/t-mbox-util.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++-- dirmngr/server.c | 12 ++++++++++++ g10/call-dirmngr.c | 10 +++++++++- 5 files changed, 114 insertions(+), 3 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Sat Jul 28 09:53:23 2018 From: cvs at cvs.gnupg.org (by Jussi Kivilinna) Date: Sat, 28 Jul 2018 09:53:23 +0200 Subject: [git] GCRYPT - branch, master, updated. libgcrypt-1.8.1-86-g86e5e06 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU crypto library". The branch, master has been updated via 86e5e06a97ae13b8bbf6923ecc76e02b9c429b46 (commit) from 9660c3fafd732b1857bb2697c6f43aed077b9ad6 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 86e5e06a97ae13b8bbf6923ecc76e02b9c429b46 Author: Jussi Kivilinna Date: Sat Jul 21 11:56:46 2018 +0300 Add size optimized cipher block copy and xor functions * cipher/bufhelp.h (buf_get_he32, buf_put_he32, buf_get_he64) (buf_put_he64): New. * cipher/cipher-internal.h (cipher_block_cpy, cipher_block_xor) (cipher_block_xor_1, cipher_block_xor_2dst, cipher_block_xor_n_copy_2) (cipher_block_xor_n_copy): New. * cipher/cipher-gcm-intel-pclmul.c (_gcry_ghash_setup_intel_pclmul): Use assembly for swapping endianness instead of buf_get_be64 and buf_cpy. * cipher/blowfish.c: Use new cipher_block_* functions for cipher block sized buf_cpy/xor* operations. * cipher/camellia-glue.c: Ditto. * cipher/cast5.c: Ditto. * cipher/cipher-aeswrap.c: Ditto. * cipher/cipher-cbc.c: Ditto. * cipher/cipher-ccm.c: Ditto. * cipher/cipher-cfb.c: Ditto. * cipher/cipher-cmac.c: Ditto. * cipher/cipher-ctr.c: Ditto. * cipher/cipher-eax.c: Ditto. * cipher/cipher-gcm.c: Ditto. * cipher/cipher-ocb.c: Ditto. * cipher/cipher-ofb.c: Ditto. * cipher/cipher-xts.c: Ditto. * cipher/des.c: Ditto. * cipher/rijndael.c: Ditto. * cipher/serpent.c: Ditto. * cipher/twofish.c: Ditto. -- This commit adds size-optimized functions for copying and xoring cipher block sized buffers. These functions also allow GCC to use inline auto-vectorization for block cipher copying and xoring on higher optimization levels. Signed-off-by: Jussi Kivilinna diff --git a/cipher/blowfish.c b/cipher/blowfish.c index 2d91820..f032c5c 100644 --- a/cipher/blowfish.c +++ b/cipher/blowfish.c @@ -37,6 +37,7 @@ #include "g10lib.h" #include "cipher.h" #include "bufhelp.h" +#include "cipher-internal.h" #include "cipher-selftest.h" #define BLOWFISH_BLOCKSIZE 8 @@ -660,7 +661,7 @@ _gcry_blowfish_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg, /* Encrypt the counter. */ do_encrypt_block(ctx, tmpbuf, ctr); /* XOR the input with the encrypted counter and store in output. */ - buf_xor(outbuf, tmpbuf, inbuf, BLOWFISH_BLOCKSIZE); + cipher_block_xor(outbuf, tmpbuf, inbuf, BLOWFISH_BLOCKSIZE); outbuf += BLOWFISH_BLOCKSIZE; inbuf += BLOWFISH_BLOCKSIZE; /* Increment the counter. */ @@ -728,7 +729,7 @@ _gcry_blowfish_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, the intermediate result to SAVEBUF. */ do_decrypt_block (ctx, savebuf, inbuf); - buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, BLOWFISH_BLOCKSIZE); + cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, BLOWFISH_BLOCKSIZE); inbuf += BLOWFISH_BLOCKSIZE; outbuf += BLOWFISH_BLOCKSIZE; } @@ -785,7 +786,7 @@ _gcry_blowfish_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg, for ( ;nblocks; nblocks-- ) { do_encrypt_block(ctx, iv, iv); - buf_xor_n_copy(outbuf, iv, inbuf, BLOWFISH_BLOCKSIZE); + cipher_block_xor_n_copy(outbuf, iv, inbuf, BLOWFISH_BLOCKSIZE); outbuf += BLOWFISH_BLOCKSIZE; inbuf += BLOWFISH_BLOCKSIZE; } diff --git a/cipher/bufhelp.h b/cipher/bufhelp.h index 83d3f53..4e97c4d 100644 --- a/cipher/bufhelp.h +++ b/cipher/bufhelp.h @@ -450,7 +450,21 @@ static inline void buf_put_le64(void *_buf, u64 val) out->a = le_bswap64(val); } - #endif /*BUFHELP_UNALIGNED_ACCESS*/ + +/* Host-endian get/put macros */ +#ifdef WORDS_BIGENDIAN +# define buf_get_he32 buf_get_be32 +# define buf_put_he32 buf_put_be32 +# define buf_get_he64 buf_get_be64 +# define buf_put_he64 buf_put_be64 +#else +# define buf_get_he32 buf_get_le32 +# define buf_put_he32 buf_put_le32 +# define buf_get_he64 buf_get_le64 +# define buf_put_he64 buf_put_le64 +#endif + + #endif /*GCRYPT_BUFHELP_H*/ diff --git a/cipher/camellia-glue.c b/cipher/camellia-glue.c index 22df214..69b240b 100644 --- a/cipher/camellia-glue.c +++ b/cipher/camellia-glue.c @@ -430,7 +430,7 @@ _gcry_camellia_ctr_enc(void *context, unsigned char *ctr, /* Encrypt the counter. */ Camellia_EncryptBlock(ctx->keybitlength, ctr, ctx->keytable, tmpbuf); /* XOR the input with the encrypted counter and store in output. */ - buf_xor(outbuf, tmpbuf, inbuf, CAMELLIA_BLOCK_SIZE); + cipher_block_xor(outbuf, tmpbuf, inbuf, CAMELLIA_BLOCK_SIZE); outbuf += CAMELLIA_BLOCK_SIZE; inbuf += CAMELLIA_BLOCK_SIZE; /* Increment the counter. */ @@ -523,7 +523,8 @@ _gcry_camellia_cbc_dec(void *context, unsigned char *iv, the intermediate result to SAVEBUF. */ Camellia_DecryptBlock(ctx->keybitlength, inbuf, ctx->keytable, savebuf); - buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, CAMELLIA_BLOCK_SIZE); + cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, + CAMELLIA_BLOCK_SIZE); inbuf += CAMELLIA_BLOCK_SIZE; outbuf += CAMELLIA_BLOCK_SIZE; } @@ -605,7 +606,7 @@ _gcry_camellia_cfb_dec(void *context, unsigned char *iv, for ( ;nblocks; nblocks-- ) { Camellia_EncryptBlock(ctx->keybitlength, iv, ctx->keytable, iv); - buf_xor_n_copy(outbuf, iv, inbuf, CAMELLIA_BLOCK_SIZE); + cipher_block_xor_n_copy(outbuf, iv, inbuf, CAMELLIA_BLOCK_SIZE); outbuf += CAMELLIA_BLOCK_SIZE; inbuf += CAMELLIA_BLOCK_SIZE; } diff --git a/cipher/cast5.c b/cipher/cast5.c index e7d324b..49e8b78 100644 --- a/cipher/cast5.c +++ b/cipher/cast5.c @@ -44,6 +44,7 @@ #include "cipher.h" #include "bithelp.h" #include "bufhelp.h" +#include "cipher-internal.h" #include "cipher-selftest.h" /* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */ @@ -634,7 +635,7 @@ _gcry_cast5_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg, /* Encrypt the counter. */ do_encrypt_block(ctx, tmpbuf, ctr); /* XOR the input with the encrypted counter and store in output. */ - buf_xor(outbuf, tmpbuf, inbuf, CAST5_BLOCKSIZE); + cipher_block_xor(outbuf, tmpbuf, inbuf, CAST5_BLOCKSIZE); outbuf += CAST5_BLOCKSIZE; inbuf += CAST5_BLOCKSIZE; /* Increment the counter. */ @@ -702,7 +703,7 @@ _gcry_cast5_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, the intermediate result to SAVEBUF. */ do_decrypt_block (ctx, savebuf, inbuf); - buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, CAST5_BLOCKSIZE); + cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, CAST5_BLOCKSIZE); inbuf += CAST5_BLOCKSIZE; outbuf += CAST5_BLOCKSIZE; } @@ -758,7 +759,7 @@ _gcry_cast5_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg, for ( ;nblocks; nblocks-- ) { do_encrypt_block(ctx, iv, iv); - buf_xor_n_copy(outbuf, iv, inbuf, CAST5_BLOCKSIZE); + cipher_block_xor_n_copy(outbuf, iv, inbuf, CAST5_BLOCKSIZE); outbuf += CAST5_BLOCKSIZE; inbuf += CAST5_BLOCKSIZE; } diff --git a/cipher/cipher-aeswrap.c b/cipher/cipher-aeswrap.c index a8d0e03..c182657 100644 --- a/cipher/cipher-aeswrap.c +++ b/cipher/cipher-aeswrap.c @@ -99,7 +99,7 @@ _gcry_cipher_aeswrap_encrypt (gcry_cipher_hd_t c, break; } /* A := MSB_64(B) ^ t */ - buf_xor(a, b, t, 8); + cipher_block_xor(a, b, t, 8); /* R[i] := LSB_64(B) */ memcpy (r+i*8, b+8, 8); } @@ -170,7 +170,7 @@ _gcry_cipher_aeswrap_decrypt (gcry_cipher_hd_t c, for (i = n; i >= 1; i--) { /* B := AES_k^1( (A ^ t)| R[i] ) */ - buf_xor(b, a, t, 8); + cipher_block_xor(b, a, t, 8); memcpy (b+8, r+(i-1)*8, 8); nburn = c->spec->decrypt (&c->context.c, b, b); burn = nburn > burn ? nburn : burn; diff --git a/cipher/cipher-cbc.c b/cipher/cipher-cbc.c index 2ad39d0..d4df1e7 100644 --- a/cipher/cipher-cbc.c +++ b/cipher/cipher-cbc.c @@ -56,7 +56,7 @@ cbc_encrypt_inner(gcry_cipher_hd_t c, unsigned char *outbuf, for (n=0; n < nblocks; n++ ) { - buf_xor (outbuf, inbuf, ivp, blocksize); + cipher_block_xor (outbuf, inbuf, ivp, blocksize); nburn = enc_fn ( &c->context.c, outbuf, outbuf ); burn = nburn > burn ? nburn : burn; ivp = outbuf; @@ -66,7 +66,7 @@ cbc_encrypt_inner(gcry_cipher_hd_t c, unsigned char *outbuf, } if (ivp != c->u_iv.iv) - buf_cpy (c->u_iv.iv, ivp, blocksize); + cipher_block_cpy (c->u_iv.iv, ivp, blocksize); } return burn; @@ -156,7 +156,7 @@ _gcry_cipher_cbc_cts_encrypt (gcry_cipher_hd_t c, nburn = enc_fn (&c->context.c, outbuf, outbuf); burn = nburn > burn ? nburn : burn; - buf_cpy (c->u_iv.iv, outbuf, blocksize); + cipher_block_cpy (c->u_iv.iv, outbuf, blocksize); } if (burn > 0) @@ -190,7 +190,8 @@ cbc_decrypt_inner(gcry_cipher_hd_t c, unsigned char *outbuf, storage here because it is not used otherwise. */ nburn = dec_fn ( &c->context.c, c->lastiv, inbuf ); burn = nburn > burn ? nburn : burn; - buf_xor_n_copy_2 (outbuf, c->lastiv, c->u_iv.iv, inbuf, blocksize); + cipher_block_xor_n_copy_2 (outbuf, c->lastiv, c->u_iv.iv, inbuf, + blocksize); inbuf += blocksize; outbuf += blocksize; } @@ -252,7 +253,7 @@ _gcry_cipher_cbc_cts_decrypt (gcry_cipher_hd_t c, nblocks--; if ((inbuflen & blocksize_mask) == 0) nblocks--; - buf_cpy (c->lastiv, c->u_iv.iv, blocksize); + cipher_block_cpy (c->lastiv, c->u_iv.iv, blocksize); } burn = cbc_decrypt_inner(c, outbuf, inbuf, nblocks, blocksize); @@ -268,7 +269,7 @@ _gcry_cipher_cbc_cts_decrypt (gcry_cipher_hd_t c, else restbytes = inbuflen & blocksize_mask; - buf_cpy (c->lastiv, c->u_iv.iv, blocksize ); /* Save Cn-2. */ + cipher_block_cpy (c->lastiv, c->u_iv.iv, blocksize ); /* Save Cn-2. */ buf_cpy (c->u_iv.iv, inbuf + blocksize, restbytes ); /* Save Cn. */ nburn = dec_fn ( &c->context.c, outbuf, inbuf ); @@ -280,7 +281,7 @@ _gcry_cipher_cbc_cts_decrypt (gcry_cipher_hd_t c, c->u_iv.iv[i] = outbuf[i]; nburn = dec_fn (&c->context.c, outbuf, c->u_iv.iv); burn = nburn > burn ? nburn : burn; - buf_xor(outbuf, outbuf, c->lastiv, blocksize); + cipher_block_xor(outbuf, outbuf, c->lastiv, blocksize); /* c->lastiv is now really lastlastiv, does this matter? */ } diff --git a/cipher/cipher-ccm.c b/cipher/cipher-ccm.c index d7f14d8..e71c6f1 100644 --- a/cipher/cipher-ccm.c +++ b/cipher/cipher-ccm.c @@ -67,7 +67,8 @@ do_cbc_mac (gcry_cipher_hd_t c, const unsigned char *inbuf, size_t inlen, if (unused > 0) { /* Process one block from macbuf. */ - buf_xor(c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.macbuf, blocksize); + cipher_block_xor(c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.macbuf, + blocksize); set_burn (burn, enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv )); unused = 0; @@ -86,7 +87,7 @@ do_cbc_mac (gcry_cipher_hd_t c, const unsigned char *inbuf, size_t inlen, { while (inlen >= blocksize) { - buf_xor(c->u_iv.iv, c->u_iv.iv, inbuf, blocksize); + cipher_block_xor(c->u_iv.iv, c->u_iv.iv, inbuf, blocksize); set_burn (burn, enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv )); @@ -272,7 +273,7 @@ _gcry_cipher_ccm_tag (gcry_cipher_hd_t c, unsigned char *outbuf, burn = do_cbc_mac (c, NULL, 0, 1); /* Perform final padding. */ /* Add S_0 */ - buf_xor (c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.s0, 16); + cipher_block_xor (c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.s0, 16); wipememory (c->u_ctr.ctr, 16); wipememory (c->u_mode.ccm.s0, 16); diff --git a/cipher/cipher-cfb.c b/cipher/cipher-cfb.c index 7f00aee..012c6c1 100644 --- a/cipher/cipher-cfb.c +++ b/cipher/cipher-cfb.c @@ -87,7 +87,7 @@ _gcry_cipher_cfb_encrypt (gcry_cipher_hd_t c, nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; /* XOR the input with the IV and store input into IV. */ - buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize); + cipher_block_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize); outbuf += blocksize; inbuf += blocksize; inbuflen -= blocksize; @@ -97,11 +97,11 @@ _gcry_cipher_cfb_encrypt (gcry_cipher_hd_t c, if ( inbuflen >= blocksize ) { /* Save the current IV and then encrypt the IV. */ - buf_cpy( c->lastiv, c->u_iv.iv, blocksize ); + cipher_block_cpy( c->lastiv, c->u_iv.iv, blocksize ); nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; /* XOR the input with the IV and store input into IV */ - buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize); + cipher_block_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize); outbuf += blocksize; inbuf += blocksize; inbuflen -= blocksize; @@ -109,7 +109,7 @@ _gcry_cipher_cfb_encrypt (gcry_cipher_hd_t c, if ( inbuflen ) { /* Save the current IV and then encrypt the IV. */ - buf_cpy( c->lastiv, c->u_iv.iv, blocksize ); + cipher_block_cpy( c->lastiv, c->u_iv.iv, blocksize ); nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; c->unused = blocksize; @@ -185,7 +185,7 @@ _gcry_cipher_cfb_decrypt (gcry_cipher_hd_t c, nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; /* XOR the input with the IV and store input into IV. */ - buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize); + cipher_block_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize); outbuf += blocksize; inbuf += blocksize; inbuflen -= blocksize; @@ -195,11 +195,11 @@ _gcry_cipher_cfb_decrypt (gcry_cipher_hd_t c, if (inbuflen >= blocksize ) { /* Save the current IV and then encrypt the IV. */ - buf_cpy ( c->lastiv, c->u_iv.iv, blocksize); + cipher_block_cpy ( c->lastiv, c->u_iv.iv, blocksize); nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; /* XOR the input with the IV and store input into IV */ - buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize); + cipher_block_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize); outbuf += blocksize; inbuf += blocksize; inbuflen -= blocksize; @@ -208,7 +208,7 @@ _gcry_cipher_cfb_decrypt (gcry_cipher_hd_t c, if (inbuflen) { /* Save the current IV and then encrypt the IV. */ - buf_cpy ( c->lastiv, c->u_iv.iv, blocksize ); + cipher_block_cpy ( c->lastiv, c->u_iv.iv, blocksize ); nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; c->unused = blocksize; diff --git a/cipher/cipher-cmac.c b/cipher/cipher-cmac.c index 321ab9e..da550c3 100644 --- a/cipher/cipher-cmac.c +++ b/cipher/cipher-cmac.c @@ -66,7 +66,7 @@ _gcry_cmac_write (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx, for (; inlen && ctx->mac_unused < blocksize; inlen--) ctx->macbuf[ctx->mac_unused++] = *inbuf++; - buf_xor (ctx->u_iv.iv, ctx->u_iv.iv, ctx->macbuf, blocksize); + cipher_block_xor (ctx->u_iv.iv, ctx->u_iv.iv, ctx->macbuf, blocksize); set_burn (burn, enc_fn (&c->context.c, ctx->u_iv.iv, ctx->u_iv.iv)); ctx->mac_unused = 0; @@ -86,7 +86,7 @@ _gcry_cmac_write (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx, else while (inlen > blocksize) { - buf_xor (ctx->u_iv.iv, ctx->u_iv.iv, inbuf, blocksize); + cipher_block_xor (ctx->u_iv.iv, ctx->u_iv.iv, inbuf, blocksize); set_burn (burn, enc_fn (&c->context.c, ctx->u_iv.iv, ctx->u_iv.iv)); inlen -= blocksize; inbuf += blocksize; @@ -181,9 +181,9 @@ _gcry_cmac_final (gcry_cipher_hd_t c, gcry_cmac_context_t *ctx) ctx->macbuf[count++] = 0; } - buf_xor (ctx->macbuf, ctx->macbuf, subkey, blocksize); + cipher_block_xor (ctx->macbuf, ctx->macbuf, subkey, blocksize); - buf_xor (ctx->u_iv.iv, ctx->u_iv.iv, ctx->macbuf, blocksize); + cipher_block_xor (ctx->u_iv.iv, ctx->u_iv.iv, ctx->macbuf, blocksize); burn = c->spec->encrypt (&c->context.c, ctx->u_iv.iv, ctx->u_iv.iv); if (burn) _gcry_burn_stack (burn + 4 * sizeof (void *)); diff --git a/cipher/cipher-ctr.c b/cipher/cipher-ctr.c index b54fb5a..2df0b8c 100644 --- a/cipher/cipher-ctr.c +++ b/cipher/cipher-ctr.c @@ -77,24 +77,38 @@ _gcry_cipher_ctr_encrypt (gcry_cipher_hd_t c, { unsigned char tmp[MAX_BLOCKSIZE]; - do { - nburn = enc_fn (&c->context.c, tmp, c->u_ctr.ctr); - burn = nburn > burn ? nburn : burn; - - for (i = blocksize; i > 0; i--) - { - c->u_ctr.ctr[i-1]++; - if (c->u_ctr.ctr[i-1] != 0) - break; - } - - n = blocksize < inbuflen ? blocksize : inbuflen; - buf_xor(outbuf, inbuf, tmp, n); - - inbuflen -= n; - outbuf += n; - inbuf += n; - } while (inbuflen); + do + { + nburn = enc_fn (&c->context.c, tmp, c->u_ctr.ctr); + burn = nburn > burn ? nburn : burn; + + for (i = blocksize; i > 0; i--) + { + c->u_ctr.ctr[i-1]++; + if (c->u_ctr.ctr[i-1] != 0) + break; + } + + if (inbuflen < blocksize) + break; + n = blocksize; + cipher_block_xor(outbuf, inbuf, tmp, blocksize); + + inbuflen -= n; + outbuf += n; + inbuf += n; + } + while (inbuflen); + + if (inbuflen) + { + n = inbuflen; + buf_xor(outbuf, inbuf, tmp, inbuflen); + + inbuflen -= n; + outbuf += n; + inbuf += n; + } /* Save the unused bytes of the counter. */ c->unused = blocksize - n; diff --git a/cipher/cipher-eax.c b/cipher/cipher-eax.c index 1ce4797..3b17bb6 100644 --- a/cipher/cipher-eax.c +++ b/cipher/cipher-eax.c @@ -157,8 +157,8 @@ _gcry_cipher_eax_set_nonce (gcry_cipher_hd_t c, const byte *nonce, if (err != 0) return err; - buf_cpy (c->u_iv.iv, nonce_cmac.u_iv.iv, MAX_BLOCKSIZE); - buf_cpy (c->u_ctr.ctr, nonce_cmac.u_iv.iv, MAX_BLOCKSIZE); + cipher_block_cpy (c->u_iv.iv, nonce_cmac.u_iv.iv, MAX_BLOCKSIZE); + cipher_block_cpy (c->u_ctr.ctr, nonce_cmac.u_iv.iv, MAX_BLOCKSIZE); wipememory (&nonce_cmac, sizeof(nonce_cmac)); @@ -201,9 +201,10 @@ _gcry_cipher_eax_tag (gcry_cipher_hd_t c, if (err != 0) return err; - buf_xor_1 (c->u_iv.iv, c->u_mode.eax.cmac_header.u_iv.iv, MAX_BLOCKSIZE); - buf_xor_1 (c->u_iv.iv, c->u_mode.eax.cmac_ciphertext.u_iv.iv, - MAX_BLOCKSIZE); + cipher_block_xor_1 (c->u_iv.iv, c->u_mode.eax.cmac_header.u_iv.iv, + MAX_BLOCKSIZE); + cipher_block_xor_1 (c->u_iv.iv, c->u_mode.eax.cmac_ciphertext.u_iv.iv, + MAX_BLOCKSIZE); _gcry_cmac_reset (&c->u_mode.eax.cmac_header); _gcry_cmac_reset (&c->u_mode.eax.cmac_ciphertext); diff --git a/cipher/cipher-gcm-intel-pclmul.c b/cipher/cipher-gcm-intel-pclmul.c index a327249..0f26277 100644 --- a/cipher/cipher-gcm-intel-pclmul.c +++ b/cipher/cipher-gcm-intel-pclmul.c @@ -248,7 +248,8 @@ static inline void gfmul_pclmul_aggr4(void) void _gcry_ghash_setup_intel_pclmul (gcry_cipher_hd_t c) { - u64 tmp[2]; + static const unsigned char be_mask[16] __attribute__ ((aligned (16))) = + { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; #if defined(__x86_64__) && defined(__WIN64__) char win64tmp[3 * 16]; @@ -262,15 +263,19 @@ _gcry_ghash_setup_intel_pclmul (gcry_cipher_hd_t c) #endif /* Swap endianness of hsub. */ - tmp[0] = buf_get_be64(c->u_mode.gcm.u_ghash_key.key + 8); - tmp[1] = buf_get_be64(c->u_mode.gcm.u_ghash_key.key + 0); - buf_cpy (c->u_mode.gcm.u_ghash_key.key, tmp, GCRY_GCM_BLOCK_LEN); + asm volatile ("movdqu (%[key]), %%xmm0\n\t" + "pshufb %[be_mask], %%xmm0\n\t" + "movdqu %%xmm0, (%[key])\n\t" + : + : [key] "r" (c->u_mode.gcm.u_ghash_key.key), + [be_mask] "m" (*be_mask) + : "memory"); #ifdef __x86_64__ - asm volatile ("movdqu %[h_1], %%xmm0\n\t" - "movdqa %%xmm0, %%xmm1\n\t" + asm volatile ("movdqa %%xmm0, %%xmm1\n\t" : - : [h_1] "m" (*tmp)); + : + : "memory"); gfmul_pclmul (); /* H?H => H? */ @@ -324,8 +329,6 @@ _gcry_ghash_setup_intel_pclmul (gcry_cipher_hd_t c) ::: "cc" ); #endif #endif - - wipememory (tmp, sizeof(tmp)); } diff --git a/cipher/cipher-gcm.c b/cipher/cipher-gcm.c index 6169d14..32ec9fa 100644 --- a/cipher/cipher-gcm.c +++ b/cipher/cipher-gcm.c @@ -150,7 +150,7 @@ do_ghash (unsigned char *result, const unsigned char *buf, const u64 *gcmM) u32 A; int i; - buf_xor (V, result, buf, 16); + cipher_block_xor (V, result, buf, 16); V[0] = be_bswap64 (V[0]); V[1] = be_bswap64 (V[1]); @@ -259,7 +259,7 @@ do_ghash (unsigned char *result, const unsigned char *buf, const u32 *gcmM) u32 T[3]; int i; - buf_xor (V, result, buf, 16); /* V is big-endian */ + cipher_block_xor (V, result, buf, 16); /* V is big-endian */ /* First round can be manually tweaked based on fact that 'tmp' is zero. */ i = 15; @@ -342,7 +342,7 @@ do_ghash (unsigned char *hsub, unsigned char *result, const unsigned char *buf) #else unsigned long T[4]; - buf_xor (V, result, buf, 16); + cipher_block_xor (V, result, buf, 16); for (i = 0; i < 4; i++) { V[i] = (V[i] & 0x00ff00ff) << 8 | (V[i] & 0xff00ff00) >> 8; @@ -358,7 +358,7 @@ do_ghash (unsigned char *hsub, unsigned char *result, const unsigned char *buf) for (j = 0x80; j; j >>= 1) { if (hsub[i] & j) - buf_xor (p, p, V, 16); + cipher_block_xor (p, p, V, 16); if (bshift (V)) V[0] ^= 0xe1000000; } @@ -598,7 +598,7 @@ gcm_ctr_encrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen, } fix_ctr = 1; - buf_cpy(ctr_copy, c->u_ctr.ctr, GCRY_GCM_BLOCK_LEN); + cipher_block_cpy(ctr_copy, c->u_ctr.ctr, GCRY_GCM_BLOCK_LEN); } } @@ -928,8 +928,8 @@ _gcry_cipher_gcm_tag (gcry_cipher_hd_t c, /* Add bitlengths to tag. */ do_ghash_buf(c, c->u_mode.gcm.u_tag.tag, (byte*)bitlengths, GCRY_GCM_BLOCK_LEN, 1); - buf_xor (c->u_mode.gcm.u_tag.tag, c->u_mode.gcm.tagiv, - c->u_mode.gcm.u_tag.tag, GCRY_GCM_BLOCK_LEN); + cipher_block_xor (c->u_mode.gcm.u_tag.tag, c->u_mode.gcm.tagiv, + c->u_mode.gcm.u_tag.tag, GCRY_GCM_BLOCK_LEN); c->marks.tag = 1; wipememory (bitlengths, sizeof (bitlengths)); diff --git a/cipher/cipher-internal.h b/cipher/cipher-internal.h index 6d87561..f93363b 100644 --- a/cipher/cipher-internal.h +++ b/cipher/cipher-internal.h @@ -603,4 +603,145 @@ static inline unsigned int _gcry_blocksize_shift(gcry_cipher_hd_t c) } +/* Optimized function for cipher block copying */ +static inline void +cipher_block_cpy(void *_dst, const void *_src, size_t blocksize) +{ + byte *dst = _dst; + const byte *src = _src; + u64 s[2]; + + if (blocksize == 8) + { + buf_put_he64(dst + 0, buf_get_he64(src + 0)); + } + else /* blocksize == 16 */ + { + s[0] = buf_get_he64(src + 0); + s[1] = buf_get_he64(src + 8); + buf_put_he64(dst + 0, s[0]); + buf_put_he64(dst + 8, s[1]); + } +} + + +/* Optimized function for cipher block xoring */ +static inline void +cipher_block_xor(void *_dst, const void *_src1, const void *_src2, + size_t blocksize) +{ + byte *dst = _dst; + const byte *src1 = _src1; + const byte *src2 = _src2; + u64 s1[2]; + u64 s2[2]; + + if (blocksize == 8) + { + buf_put_he64(dst + 0, buf_get_he64(src1 + 0) ^ buf_get_he64(src2 + 0)); + } + else /* blocksize == 16 */ + { + s1[0] = buf_get_he64(src1 + 0); + s1[1] = buf_get_he64(src1 + 8); + s2[0] = buf_get_he64(src2 + 0); + s2[1] = buf_get_he64(src2 + 8); + buf_put_he64(dst + 0, s1[0] ^ s2[0]); + buf_put_he64(dst + 8, s1[1] ^ s2[1]); + } +} + + +/* Optimized function for in-place cipher block xoring */ +static inline void +cipher_block_xor_1(void *_dst, const void *_src, size_t blocksize) +{ + cipher_block_xor (_dst, _dst, _src, blocksize); +} + + +/* Optimized function for cipher block xoring with two destination cipher + blocks. Used mainly by CFB mode encryption. */ +static inline void +cipher_block_xor_2dst(void *_dst1, void *_dst2, const void *_src, + size_t blocksize) +{ + byte *dst1 = _dst1; + byte *dst2 = _dst2; + const byte *src = _src; + u64 d2[2]; + u64 s[2]; + + if (blocksize == 8) + { + d2[0] = buf_get_he64(dst2 + 0) ^ buf_get_he64(src + 0); + buf_put_he64(dst2 + 0, d2[0]); + buf_put_he64(dst1 + 0, d2[0]); + } + else /* blocksize == 16 */ + { + s[0] = buf_get_he64(src + 0); + s[1] = buf_get_he64(src + 8); + d2[0] = buf_get_he64(dst2 + 0); + d2[1] = buf_get_he64(dst2 + 8); + d2[0] = d2[0] ^ s[0]; + d2[1] = d2[1] ^ s[1]; + buf_put_he64(dst2 + 0, d2[0]); + buf_put_he64(dst2 + 8, d2[1]); + buf_put_he64(dst1 + 0, d2[0]); + buf_put_he64(dst1 + 8, d2[1]); + } +} + + +/* Optimized function for combined cipher block xoring and copying. + Used by mainly CBC mode decryption. */ +static inline void +cipher_block_xor_n_copy_2(void *_dst_xor, const void *_src_xor, + void *_srcdst_cpy, const void *_src_cpy, + size_t blocksize) +{ + byte *dst_xor = _dst_xor; + byte *srcdst_cpy = _srcdst_cpy; + const byte *src_xor = _src_xor; + const byte *src_cpy = _src_cpy; + u64 sc[2]; + u64 sx[2]; + u64 sdc[2]; + + if (blocksize == 8) + { + sc[0] = buf_get_he64(src_cpy + 0); + buf_put_he64(dst_xor + 0, + buf_get_he64(srcdst_cpy + 0) ^ buf_get_he64(src_xor + 0)); + buf_put_he64(srcdst_cpy + 0, sc[0]); + } + else /* blocksize == 16 */ + { + sc[0] = buf_get_he64(src_cpy + 0); + sc[1] = buf_get_he64(src_cpy + 8); + sx[0] = buf_get_he64(src_xor + 0); + sx[1] = buf_get_he64(src_xor + 8); + sdc[0] = buf_get_he64(srcdst_cpy + 0); + sdc[1] = buf_get_he64(srcdst_cpy + 8); + sx[0] ^= sdc[0]; + sx[1] ^= sdc[1]; + buf_put_he64(dst_xor + 0, sx[0]); + buf_put_he64(dst_xor + 8, sx[1]); + buf_put_he64(srcdst_cpy + 0, sc[0]); + buf_put_he64(srcdst_cpy + 8, sc[1]); + } +} + + +/* Optimized function for combined cipher block xoring and copying. + Used by mainly CFB mode decryption. */ +static inline void +cipher_block_xor_n_copy(void *_dst_xor, void *_srcdst_cpy, const void *_src, + size_t blocksize) +{ + cipher_block_xor_n_copy_2(_dst_xor, _src, _srcdst_cpy, _src, blocksize); +} + + #endif /*G10_CIPHER_INTERNAL_H*/ diff --git a/cipher/cipher-ocb.c b/cipher/cipher-ocb.c index db42aaf..f71520a 100644 --- a/cipher/cipher-ocb.c +++ b/cipher/cipher-ocb.c @@ -82,7 +82,7 @@ static void double_block_cpy (unsigned char *d, const unsigned char *s) { if (d != s) - buf_cpy (d, s, OCB_BLOCK_LEN); + cipher_block_cpy (d, s, OCB_BLOCK_LEN); double_block (d); } @@ -181,8 +181,8 @@ _gcry_cipher_ocb_set_nonce (gcry_cipher_hd_t c, const unsigned char *nonce, nburn = c->spec->encrypt (&c->context.c, ktop, ktop); burn = nburn > burn ? nburn : burn; /* Stretch = Ktop || (Ktop[1..64] xor Ktop[9..72]) */ - buf_cpy (stretch, ktop, OCB_BLOCK_LEN); - buf_xor (stretch + OCB_BLOCK_LEN, ktop, ktop + 1, 8); + cipher_block_cpy (stretch, ktop, OCB_BLOCK_LEN); + cipher_block_xor (stretch + OCB_BLOCK_LEN, ktop, ktop + 1, 8); /* Offset_0 = Stretch[1+bottom..128+bottom] (We use the IV field to store the offset) */ bit_copy (c->u_iv.iv, stretch, bottom, OCB_BLOCK_LEN); @@ -267,18 +267,18 @@ _gcry_cipher_ocb_authenticate (gcry_cipher_hd_t c, const unsigned char *abuf, } else { - buf_cpy (l_tmp, ocb_get_l (c, c->u_mode.ocb.aad_nblocks), - OCB_BLOCK_LEN); + cipher_block_cpy (l_tmp, ocb_get_l (c, c->u_mode.ocb.aad_nblocks), + OCB_BLOCK_LEN); } /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ - buf_xor_1 (c->u_mode.ocb.aad_offset, l_tmp, OCB_BLOCK_LEN); + cipher_block_xor_1 (c->u_mode.ocb.aad_offset, l_tmp, OCB_BLOCK_LEN); /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */ - buf_xor (l_tmp, c->u_mode.ocb.aad_offset, - c->u_mode.ocb.aad_leftover, OCB_BLOCK_LEN); + cipher_block_xor (l_tmp, c->u_mode.ocb.aad_offset, + c->u_mode.ocb.aad_leftover, OCB_BLOCK_LEN); nburn = c->spec->encrypt (&c->context.c, l_tmp, l_tmp); burn = nburn > burn ? nburn : burn; - buf_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); + cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); c->u_mode.ocb.aad_nleftover = 0; } @@ -309,12 +309,13 @@ _gcry_cipher_ocb_authenticate (gcry_cipher_hd_t c, const unsigned char *abuf, ocb_get_L_big(c, c->u_mode.ocb.aad_nblocks, l_tmp); /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ - buf_xor_1 (c->u_mode.ocb.aad_offset, l_tmp, OCB_BLOCK_LEN); + cipher_block_xor_1 (c->u_mode.ocb.aad_offset, l_tmp, OCB_BLOCK_LEN); /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */ - buf_xor (l_tmp, c->u_mode.ocb.aad_offset, abuf, OCB_BLOCK_LEN); + cipher_block_xor (l_tmp, c->u_mode.ocb.aad_offset, abuf, + OCB_BLOCK_LEN); nburn = c->spec->encrypt (&c->context.c, l_tmp, l_tmp); burn = nburn > burn ? nburn : burn; - buf_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); + cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); abuf += OCB_BLOCK_LEN; abuflen -= OCB_BLOCK_LEN; @@ -349,14 +350,15 @@ _gcry_cipher_ocb_authenticate (gcry_cipher_hd_t c, const unsigned char *abuf, gcry_assert(c->u_mode.ocb.aad_nblocks & table_size_mask); /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ - buf_xor_1 (c->u_mode.ocb.aad_offset, - ocb_get_l (c, c->u_mode.ocb.aad_nblocks), - OCB_BLOCK_LEN); + cipher_block_xor_1 (c->u_mode.ocb.aad_offset, + ocb_get_l (c, c->u_mode.ocb.aad_nblocks), + OCB_BLOCK_LEN); /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */ - buf_xor (l_tmp, c->u_mode.ocb.aad_offset, abuf, OCB_BLOCK_LEN); + cipher_block_xor (l_tmp, c->u_mode.ocb.aad_offset, abuf, + OCB_BLOCK_LEN); nburn = c->spec->encrypt (&c->context.c, l_tmp, l_tmp); burn = nburn > burn ? nburn : burn; - buf_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); + cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); abuf += OCB_BLOCK_LEN; abuflen -= OCB_BLOCK_LEN; @@ -397,18 +399,18 @@ ocb_aad_finalize (gcry_cipher_hd_t c) if (c->u_mode.ocb.aad_nleftover) { /* Offset_* = Offset_m xor L_* */ - buf_xor_1 (c->u_mode.ocb.aad_offset, - c->u_mode.ocb.L_star, OCB_BLOCK_LEN); + cipher_block_xor_1 (c->u_mode.ocb.aad_offset, + c->u_mode.ocb.L_star, OCB_BLOCK_LEN); /* CipherInput = (A_* || 1 || zeros(127-bitlen(A_*))) xor Offset_* */ buf_cpy (l_tmp, c->u_mode.ocb.aad_leftover, c->u_mode.ocb.aad_nleftover); memset (l_tmp + c->u_mode.ocb.aad_nleftover, 0, OCB_BLOCK_LEN - c->u_mode.ocb.aad_nleftover); l_tmp[c->u_mode.ocb.aad_nleftover] = 0x80; - buf_xor_1 (l_tmp, c->u_mode.ocb.aad_offset, OCB_BLOCK_LEN); + cipher_block_xor_1 (l_tmp, c->u_mode.ocb.aad_offset, OCB_BLOCK_LEN); /* Sum = Sum_m xor ENCIPHER(K, CipherInput) */ nburn = c->spec->encrypt (&c->context.c, l_tmp, l_tmp); burn = nburn > burn ? nburn : burn; - buf_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); + cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); c->u_mode.ocb.aad_nleftover = 0; } @@ -431,7 +433,7 @@ ocb_checksum (unsigned char *chksum, const unsigned char *plainbuf, while (nblks > 0) { /* Checksum_i = Checksum_{i-1} xor P_i */ - buf_xor_1(chksum, plainbuf, OCB_BLOCK_LEN); + cipher_block_xor_1(chksum, plainbuf, OCB_BLOCK_LEN); plainbuf += OCB_BLOCK_LEN; nblks--; @@ -491,12 +493,12 @@ ocb_crypt (gcry_cipher_hd_t c, int encrypt, } /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ - buf_xor_1 (c->u_iv.iv, l_tmp, OCB_BLOCK_LEN); + cipher_block_xor_1 (c->u_iv.iv, l_tmp, OCB_BLOCK_LEN); /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */ - buf_xor (outbuf, c->u_iv.iv, inbuf, OCB_BLOCK_LEN); + cipher_block_xor (outbuf, c->u_iv.iv, inbuf, OCB_BLOCK_LEN); nburn = crypt_fn (&c->context.c, outbuf, outbuf); burn = nburn > burn ? nburn : burn; - buf_xor_1 (outbuf, c->u_iv.iv, OCB_BLOCK_LEN); + cipher_block_xor_1 (outbuf, c->u_iv.iv, OCB_BLOCK_LEN); if (!encrypt) { @@ -551,14 +553,14 @@ ocb_crypt (gcry_cipher_hd_t c, int encrypt, gcry_assert(c->u_mode.ocb.data_nblocks & table_size_mask); /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ - buf_xor_1 (c->u_iv.iv, - ocb_get_l (c, c->u_mode.ocb.data_nblocks), - OCB_BLOCK_LEN); + cipher_block_xor_1 (c->u_iv.iv, + ocb_get_l (c, c->u_mode.ocb.data_nblocks), + OCB_BLOCK_LEN); /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */ - buf_xor (outbuf, c->u_iv.iv, inbuf, OCB_BLOCK_LEN); + cipher_block_xor (outbuf, c->u_iv.iv, inbuf, OCB_BLOCK_LEN); nburn = crypt_fn (&c->context.c, outbuf, outbuf); burn = nburn > burn ? nburn : burn; - buf_xor_1 (outbuf, c->u_iv.iv, OCB_BLOCK_LEN); + cipher_block_xor_1 (outbuf, c->u_iv.iv, OCB_BLOCK_LEN); inbuf += OCB_BLOCK_LEN; inbuflen -= OCB_BLOCK_LEN; @@ -584,7 +586,7 @@ ocb_crypt (gcry_cipher_hd_t c, int encrypt, unsigned char pad[OCB_BLOCK_LEN]; /* Offset_* = Offset_m xor L_* */ - buf_xor_1 (c->u_iv.iv, c->u_mode.ocb.L_star, OCB_BLOCK_LEN); + cipher_block_xor_1 (c->u_iv.iv, c->u_mode.ocb.L_star, OCB_BLOCK_LEN); /* Pad = ENCIPHER(K, Offset_*) */ nburn = c->spec->encrypt (&c->context.c, pad, c->u_iv.iv); burn = nburn > burn ? nburn : burn; @@ -596,7 +598,7 @@ ocb_crypt (gcry_cipher_hd_t c, int encrypt, buf_cpy (l_tmp, inbuf, inbuflen); memset (l_tmp + inbuflen, 0, OCB_BLOCK_LEN - inbuflen); l_tmp[inbuflen] = 0x80; - buf_xor_1 (c->u_ctr.ctr, l_tmp, OCB_BLOCK_LEN); + cipher_block_xor_1 (c->u_ctr.ctr, l_tmp, OCB_BLOCK_LEN); /* C_* = P_* xor Pad[1..bitlen(P_*)] */ buf_xor (outbuf, inbuf, pad, inbuflen); } @@ -604,13 +606,13 @@ ocb_crypt (gcry_cipher_hd_t c, int encrypt, { /* P_* = C_* xor Pad[1..bitlen(C_*)] */ /* Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) */ - buf_cpy (l_tmp, pad, OCB_BLOCK_LEN); + cipher_block_cpy (l_tmp, pad, OCB_BLOCK_LEN); buf_cpy (l_tmp, inbuf, inbuflen); - buf_xor_1 (l_tmp, pad, OCB_BLOCK_LEN); + cipher_block_xor_1 (l_tmp, pad, OCB_BLOCK_LEN); l_tmp[inbuflen] = 0x80; buf_cpy (outbuf, l_tmp, inbuflen); - buf_xor_1 (c->u_ctr.ctr, l_tmp, OCB_BLOCK_LEN); + cipher_block_xor_1 (c->u_ctr.ctr, l_tmp, OCB_BLOCK_LEN); } } @@ -618,8 +620,10 @@ ocb_crypt (gcry_cipher_hd_t c, int encrypt, if (c->marks.finalize) { /* Tag = ENCIPHER(K, Checksum xor Offset xor L_$) xor HASH(K,A) */ - buf_xor (c->u_mode.ocb.tag, c->u_ctr.ctr, c->u_iv.iv, OCB_BLOCK_LEN); - buf_xor_1 (c->u_mode.ocb.tag, c->u_mode.ocb.L_dollar, OCB_BLOCK_LEN); + cipher_block_xor (c->u_mode.ocb.tag, c->u_ctr.ctr, c->u_iv.iv, + OCB_BLOCK_LEN); + cipher_block_xor_1 (c->u_mode.ocb.tag, c->u_mode.ocb.L_dollar, + OCB_BLOCK_LEN); nburn = c->spec->encrypt (&c->context.c, c->u_mode.ocb.tag, c->u_mode.ocb.tag); burn = nburn > burn ? nburn : burn; @@ -672,7 +676,8 @@ compute_tag_if_needed (gcry_cipher_hd_t c) if (!c->marks.tag) { ocb_aad_finalize (c); - buf_xor_1 (c->u_mode.ocb.tag, c->u_mode.ocb.aad_sum, OCB_BLOCK_LEN); + cipher_block_xor_1 (c->u_mode.ocb.tag, c->u_mode.ocb.aad_sum, + OCB_BLOCK_LEN); c->marks.tag = 1; } } diff --git a/cipher/cipher-ofb.c b/cipher/cipher-ofb.c index 419a8d0..a3fd299 100644 --- a/cipher/cipher-ofb.c +++ b/cipher/cipher-ofb.c @@ -72,7 +72,7 @@ _gcry_cipher_ofb_encrypt (gcry_cipher_hd_t c, /* Encrypt the IV (and save the current one). */ nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); burn = nburn > burn ? nburn : burn; - buf_xor(outbuf, c->u_iv.iv, inbuf, blocksize); + cipher_block_xor(outbuf, c->u_iv.iv, inbuf, blocksize); outbuf += blocksize; inbuf += blocksize; inbuflen -= blocksize; diff --git a/cipher/cipher-xts.c b/cipher/cipher-xts.c index 045b353..0522a27 100644 --- a/cipher/cipher-xts.c +++ b/cipher/cipher-xts.c @@ -107,10 +107,10 @@ _gcry_cipher_xts_crypt (gcry_cipher_hd_t c, while (nblocks) { /* Xor-Encrypt/Decrypt-Xor block. */ - buf_xor (tmp.x64, inbuf, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); + cipher_block_xor (tmp.x64, inbuf, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); nburn = crypt_fn (&c->context.c, tmp.x1, tmp.x1); burn = nburn > burn ? nburn : burn; - buf_xor (outbuf, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); + cipher_block_xor (outbuf, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); outbuf += GCRY_XTS_BLOCK_LEN; inbuf += GCRY_XTS_BLOCK_LEN; @@ -133,10 +133,10 @@ _gcry_cipher_xts_crypt (gcry_cipher_hd_t c, xts_gfmul_byA (tmp.x1, c->u_ctr.ctr); /* Decrypt last block first. */ - buf_xor (outbuf, inbuf, tmp.x64, GCRY_XTS_BLOCK_LEN); + cipher_block_xor (outbuf, inbuf, tmp.x64, GCRY_XTS_BLOCK_LEN); nburn = crypt_fn (&c->context.c, outbuf, outbuf); burn = nburn > burn ? nburn : burn; - buf_xor (outbuf, outbuf, tmp.x64, GCRY_XTS_BLOCK_LEN); + cipher_block_xor (outbuf, outbuf, tmp.x64, GCRY_XTS_BLOCK_LEN); inbuflen -= GCRY_XTS_BLOCK_LEN; inbuf += GCRY_XTS_BLOCK_LEN; @@ -147,15 +147,15 @@ _gcry_cipher_xts_crypt (gcry_cipher_hd_t c, outbuf -= GCRY_XTS_BLOCK_LEN; /* Steal ciphertext from previous block. */ - buf_cpy (tmp.x64, outbuf, GCRY_XTS_BLOCK_LEN); + cipher_block_cpy (tmp.x64, outbuf, GCRY_XTS_BLOCK_LEN); buf_cpy (tmp.x64, inbuf, inbuflen); buf_cpy (outbuf + GCRY_XTS_BLOCK_LEN, outbuf, inbuflen); /* Decrypt/Encrypt last block. */ - buf_xor (tmp.x64, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); + cipher_block_xor (tmp.x64, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); nburn = crypt_fn (&c->context.c, tmp.x1, tmp.x1); burn = nburn > burn ? nburn : burn; - buf_xor (outbuf, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); + cipher_block_xor (outbuf, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); } /* Auto-increment data-unit sequence number */ diff --git a/cipher/des.c b/cipher/des.c index 0509227..a008b93 100644 --- a/cipher/des.c +++ b/cipher/des.c @@ -119,6 +119,7 @@ #include "g10lib.h" #include "cipher.h" #include "bufhelp.h" +#include "cipher-internal.h" #include "cipher-selftest.h" @@ -908,7 +909,7 @@ _gcry_3des_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg, /* Encrypt the counter. */ tripledes_ecb_encrypt (ctx, ctr, tmpbuf); /* XOR the input with the encrypted counter and store in output. */ - buf_xor(outbuf, tmpbuf, inbuf, DES_BLOCKSIZE); + cipher_block_xor(outbuf, tmpbuf, inbuf, DES_BLOCKSIZE); outbuf += DES_BLOCKSIZE; inbuf += DES_BLOCKSIZE; /* Increment the counter. */ @@ -964,7 +965,7 @@ _gcry_3des_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, the intermediate result to SAVEBUF. */ tripledes_ecb_decrypt (ctx, inbuf, savebuf); - buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, DES_BLOCKSIZE); + cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, DES_BLOCKSIZE); inbuf += DES_BLOCKSIZE; outbuf += DES_BLOCKSIZE; } @@ -1009,7 +1010,7 @@ _gcry_3des_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg, for ( ;nblocks; nblocks-- ) { tripledes_ecb_encrypt (ctx, iv, iv); - buf_xor_n_copy(outbuf, iv, inbuf, DES_BLOCKSIZE); + cipher_block_xor_n_copy(outbuf, iv, inbuf, DES_BLOCKSIZE); outbuf += DES_BLOCKSIZE; inbuf += DES_BLOCKSIZE; } diff --git a/cipher/rijndael.c b/cipher/rijndael.c index d3fcb76..d126f88 100644 --- a/cipher/rijndael.c +++ b/cipher/rijndael.c @@ -831,7 +831,7 @@ _gcry_aes_cfb_enc (void *context, unsigned char *iv, /* Encrypt the IV. */ burn_depth = encrypt_fn (ctx, iv, iv); /* XOR the input with the IV and store input into IV. */ - buf_xor_2dst(outbuf, iv, inbuf, BLOCKSIZE); + cipher_block_xor_2dst(outbuf, iv, inbuf, BLOCKSIZE); outbuf += BLOCKSIZE; inbuf += BLOCKSIZE; } @@ -891,7 +891,7 @@ _gcry_aes_cbc_enc (void *context, unsigned char *iv, for ( ;nblocks; nblocks-- ) { - buf_xor(outbuf, inbuf, last_iv, BLOCKSIZE); + cipher_block_xor(outbuf, inbuf, last_iv, BLOCKSIZE); burn_depth = encrypt_fn (ctx, outbuf, outbuf); @@ -902,7 +902,7 @@ _gcry_aes_cbc_enc (void *context, unsigned char *iv, } if (last_iv != iv) - buf_cpy (iv, last_iv, BLOCKSIZE); + cipher_block_cpy (iv, last_iv, BLOCKSIZE); } if (burn_depth) @@ -962,7 +962,7 @@ _gcry_aes_ctr_enc (void *context, unsigned char *ctr, /* Encrypt the counter. */ burn_depth = encrypt_fn (ctx, tmp.x1, ctr); /* XOR the input with the encrypted counter and store in output. */ - buf_xor(outbuf, tmp.x1, inbuf, BLOCKSIZE); + cipher_block_xor(outbuf, tmp.x1, inbuf, BLOCKSIZE); outbuf += BLOCKSIZE; inbuf += BLOCKSIZE; /* Increment the counter. */ @@ -1207,7 +1207,7 @@ _gcry_aes_cfb_dec (void *context, unsigned char *iv, for ( ;nblocks; nblocks-- ) { burn_depth = encrypt_fn (ctx, iv, iv); - buf_xor_n_copy(outbuf, iv, inbuf, BLOCKSIZE); + cipher_block_xor_n_copy(outbuf, iv, inbuf, BLOCKSIZE); outbuf += BLOCKSIZE; inbuf += BLOCKSIZE; } @@ -1272,7 +1272,7 @@ _gcry_aes_cbc_dec (void *context, unsigned char *iv, burn_depth = decrypt_fn (ctx, savebuf, inbuf); - buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, BLOCKSIZE); + cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, BLOCKSIZE); inbuf += BLOCKSIZE; outbuf += BLOCKSIZE; } @@ -1330,15 +1330,15 @@ _gcry_aes_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg, const unsigned char *l = ocb_get_l(c, i); /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ - buf_xor_1 (c->u_iv.iv, l, BLOCKSIZE); - buf_cpy (l_tmp.x1, inbuf, BLOCKSIZE); + cipher_block_xor_1 (c->u_iv.iv, l, BLOCKSIZE); + cipher_block_cpy (l_tmp.x1, inbuf, BLOCKSIZE); /* Checksum_i = Checksum_{i-1} xor P_i */ - buf_xor_1 (c->u_ctr.ctr, l_tmp.x1, BLOCKSIZE); + cipher_block_xor_1 (c->u_ctr.ctr, l_tmp.x1, BLOCKSIZE); /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */ - buf_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE); + cipher_block_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE); burn_depth = encrypt_fn (ctx, l_tmp.x1, l_tmp.x1); - buf_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE); - buf_cpy (outbuf, l_tmp.x1, BLOCKSIZE); + cipher_block_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE); + cipher_block_cpy (outbuf, l_tmp.x1, BLOCKSIZE); inbuf += BLOCKSIZE; outbuf += BLOCKSIZE; @@ -1360,15 +1360,15 @@ _gcry_aes_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg, const unsigned char *l = ocb_get_l(c, i); /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ - buf_xor_1 (c->u_iv.iv, l, BLOCKSIZE); - buf_cpy (l_tmp.x1, inbuf, BLOCKSIZE); + cipher_block_xor_1 (c->u_iv.iv, l, BLOCKSIZE); + cipher_block_cpy (l_tmp.x1, inbuf, BLOCKSIZE); /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */ - buf_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE); + cipher_block_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE); burn_depth = decrypt_fn (ctx, l_tmp.x1, l_tmp.x1); - buf_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE); + cipher_block_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE); /* Checksum_i = Checksum_{i-1} xor P_i */ - buf_xor_1 (c->u_ctr.ctr, l_tmp.x1, BLOCKSIZE); - buf_cpy (outbuf, l_tmp.x1, BLOCKSIZE); + cipher_block_xor_1 (c->u_ctr.ctr, l_tmp.x1, BLOCKSIZE); + cipher_block_cpy (outbuf, l_tmp.x1, BLOCKSIZE); inbuf += BLOCKSIZE; outbuf += BLOCKSIZE; @@ -1424,11 +1424,12 @@ _gcry_aes_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg, size_t nblocks) const unsigned char *l = ocb_get_l(c, i); /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ - buf_xor_1 (c->u_mode.ocb.aad_offset, l, BLOCKSIZE); + cipher_block_xor_1 (c->u_mode.ocb.aad_offset, l, BLOCKSIZE); /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */ - buf_xor (l_tmp.x1, c->u_mode.ocb.aad_offset, abuf, BLOCKSIZE); + cipher_block_xor (l_tmp.x1, c->u_mode.ocb.aad_offset, abuf, + BLOCKSIZE); burn_depth = encrypt_fn (ctx, l_tmp.x1, l_tmp.x1); - buf_xor_1 (c->u_mode.ocb.aad_sum, l_tmp.x1, BLOCKSIZE); + cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp.x1, BLOCKSIZE); abuf += BLOCKSIZE; } diff --git a/cipher/serpent.c b/cipher/serpent.c index 0736ad1..8e3faa7 100644 --- a/cipher/serpent.c +++ b/cipher/serpent.c @@ -1002,7 +1002,7 @@ _gcry_serpent_ctr_enc(void *context, unsigned char *ctr, /* Encrypt the counter. */ serpent_encrypt_internal(ctx, ctr, tmpbuf); /* XOR the input with the encrypted counter and store in output. */ - buf_xor(outbuf, tmpbuf, inbuf, sizeof(serpent_block_t)); + cipher_block_xor(outbuf, tmpbuf, inbuf, sizeof(serpent_block_t)); outbuf += sizeof(serpent_block_t); inbuf += sizeof(serpent_block_t); /* Increment the counter. */ @@ -1117,7 +1117,8 @@ _gcry_serpent_cbc_dec(void *context, unsigned char *iv, the intermediate result to SAVEBUF. */ serpent_decrypt_internal (ctx, inbuf, savebuf); - buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, sizeof(serpent_block_t)); + cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, + sizeof(serpent_block_t)); inbuf += sizeof(serpent_block_t); outbuf += sizeof(serpent_block_t); } @@ -1221,7 +1222,7 @@ _gcry_serpent_cfb_dec(void *context, unsigned char *iv, for ( ;nblocks; nblocks-- ) { serpent_encrypt_internal(ctx, iv, iv); - buf_xor_n_copy(outbuf, iv, inbuf, sizeof(serpent_block_t)); + cipher_block_xor_n_copy(outbuf, iv, inbuf, sizeof(serpent_block_t)); outbuf += sizeof(serpent_block_t); inbuf += sizeof(serpent_block_t); } diff --git a/cipher/twofish.c b/cipher/twofish.c index 0d187bd..51982c5 100644 --- a/cipher/twofish.c +++ b/cipher/twofish.c @@ -1161,7 +1161,7 @@ _gcry_twofish_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg, burn_stack_depth = burn; /* XOR the input with the encrypted counter and store in output. */ - buf_xor(outbuf, tmpbuf, inbuf, TWOFISH_BLOCKSIZE); + cipher_block_xor(outbuf, tmpbuf, inbuf, TWOFISH_BLOCKSIZE); outbuf += TWOFISH_BLOCKSIZE; inbuf += TWOFISH_BLOCKSIZE; /* Increment the counter. */ @@ -1243,7 +1243,7 @@ _gcry_twofish_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, if (burn > burn_stack_depth) burn_stack_depth = burn; - buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, TWOFISH_BLOCKSIZE); + cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, TWOFISH_BLOCKSIZE); inbuf += TWOFISH_BLOCKSIZE; outbuf += TWOFISH_BLOCKSIZE; } @@ -1315,7 +1315,7 @@ _gcry_twofish_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg, if (burn > burn_stack_depth) burn_stack_depth = burn; - buf_xor_n_copy(outbuf, iv, inbuf, TWOFISH_BLOCKSIZE); + cipher_block_xor_n_copy(outbuf, iv, inbuf, TWOFISH_BLOCKSIZE); outbuf += TWOFISH_BLOCKSIZE; inbuf += TWOFISH_BLOCKSIZE; } ----------------------------------------------------------------------- Summary of changes: cipher/blowfish.c | 7 +- cipher/bufhelp.h | 16 ++++- cipher/camellia-glue.c | 7 +- cipher/cast5.c | 7 +- cipher/cipher-aeswrap.c | 4 +- cipher/cipher-cbc.c | 15 +++-- cipher/cipher-ccm.c | 7 +- cipher/cipher-cfb.c | 16 ++--- cipher/cipher-cmac.c | 8 +-- cipher/cipher-ctr.c | 50 +++++++++----- cipher/cipher-eax.c | 11 +-- cipher/cipher-gcm-intel-pclmul.c | 21 +++--- cipher/cipher-gcm.c | 14 ++-- cipher/cipher-internal.h | 141 +++++++++++++++++++++++++++++++++++++++ cipher/cipher-ocb.c | 81 +++++++++++----------- cipher/cipher-ofb.c | 2 +- cipher/cipher-xts.c | 14 ++-- cipher/des.c | 7 +- cipher/rijndael.c | 43 ++++++------ cipher/serpent.c | 7 +- cipher/twofish.c | 6 +- 21 files changed, 335 insertions(+), 149 deletions(-) hooks/post-receive -- The GNU crypto library http://git.gnupg.org From cvs at cvs.gnupg.org Sun Jul 29 18:50:30 2018 From: cvs at cvs.gnupg.org (by Werner Koch) Date: Sun, 29 Jul 2018 18:50:30 +0200 Subject: [git] GnuPG - branch, STABLE-BRANCH-2-2, updated. gnupg-2.2.9-5-gf1c0d9b Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "The GNU Privacy Guard". The branch, STABLE-BRANCH-2-2 has been updated via f1c0d9bb6506eee6a3ad93ef432fe6aa5b72aabd (commit) via 8a98aa25bb4bdbfe53afd4534f6624454ca01ab0 (commit) via 4f59187a17f16d559e37a375501a0add1ca7eee8 (commit) via d43248af9242d30e95f58285e4f2a2e927aae937 (commit) from a6ce89b6eff90135854c626e51ba38204ec40da5 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit f1c0d9bb6506eee6a3ad93ef432fe6aa5b72aabd Author: Werner Koch Date: Fri Jul 27 17:35:00 2018 +0200 gpg: Set a limit for a WKD import of 256 KiB. * g10/call-dirmngr.c (MAX_WKD_RESULT_LENGTH): New. (gpg_dirmngr_wkd_get): Use it. -- WKD should return only a single key with just one UID. For key rollover 2 keys may be send. A total of 256 KiB seems to be a generous limit here. Signed-off-by: Werner Koch (cherry picked from commit e88f56f1937ac92f6a3b94e50b6db2649ec0be41) diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c index 9bc90fb..d086cef 100644 --- a/g10/call-dirmngr.c +++ b/g10/call-dirmngr.c @@ -41,6 +41,12 @@ #include "call-dirmngr.h" +/* Keys retrieved from the web key directory should be small. There + * is only one UID and we can expect that the number of subkeys is + * reasonable. So we set a generous limit of 256 KiB. */ +#define MAX_WKD_RESULT_LENGTH (256 * 1024) + + /* Parameter structure used to gather status info. Note that it is * also used for WKD requests. */ struct ks_status_parm_s @@ -1365,7 +1371,7 @@ gpg_dirmngr_wkd_get (ctrl_t ctrl, const char *name, int quick, goto leave; } - parm.memfp = es_fopenmem (0, "rwb"); + parm.memfp = es_fopenmem (MAX_WKD_RESULT_LENGTH, "rwb"); if (!parm.memfp) { err = gpg_error_from_syserror (); @@ -1373,6 +1379,8 @@ gpg_dirmngr_wkd_get (ctrl_t ctrl, const char *name, int quick, } err = assuan_transact (ctx, line, dns_cert_data_cb, &parm, NULL, NULL, ks_status_cb, &stparm); + if (gpg_err_code (err) == GPG_ERR_ENOSPC) + err = gpg_error (GPG_ERR_TOO_LARGE); if (err) goto leave; commit 8a98aa25bb4bdbfe53afd4534f6624454ca01ab0 Author: Werner Koch Date: Fri Jul 27 12:23:38 2018 +0200 dirmngr: Validate SRV records in WKD queries. * dirmngr/server.c (proc_wkd_get): Check the returned SRV record names to mitigate rogue DNS servers. -- I am not sure wether this really is very useful because the security relies on a trustworthy DNS system anyway. However, that check is easy enough to do. Signed-off-by: Werner Koch (cherry picked from commit ebe727ef596eefebb5eff7d03a98649ffc7ae3ee) diff --git a/dirmngr/server.c b/dirmngr/server.c index b7cdb24..fcf0c1a 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -887,6 +887,18 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line) if (err) goto leave; + /* Check for rogue DNS names. */ + for (i = 0; i < srvscount; i++) + { + if (!is_valid_domain_name (srvs[i].target)) + { + err = gpg_error (GPG_ERR_DNS_ADDRESS); + log_error ("rogue openpgpkey SRV record for '%s'\n", domain); + xfree (srvs); + goto leave; + } + } + /* Find the first target which also ends in DOMAIN or is equal * to DOMAIN. */ domainlen = strlen (domain); commit 4f59187a17f16d559e37a375501a0add1ca7eee8 Author: Werner Koch Date: Fri Jul 27 11:56:06 2018 +0200 common: New function to validate domain names. * common/mbox-util.c (is_valid_domain_name): New. * common/t-mbox-util.c (run_dns_test): New test. Signed-off-by: Werner Koch (cherry picked from commit ddee9f9409fb5a089883eab0fadef7b9b7e61e72) diff --git a/common/mbox-util.c b/common/mbox-util.c index c1f05b8..76255ba 100644 --- a/common/mbox-util.c +++ b/common/mbox-util.c @@ -241,3 +241,42 @@ is_valid_user_id (const char *uid) return 1; } + + +/* Returns true if STRING is a valid domain name according to the LDH + * rule. */ +int +is_valid_domain_name (const char *string) +{ + static char const ldh_chars[] = + "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-"; + const char *s; + + /* Note that we do not check the length limit of a label or the + * entire name */ + + for (s=string; *s; s++) + if (*s == '.') + { + if (string == s) + return 0; /* Dot at the start of the string. */ + /* (may also be at the end like in ".") */ + if (s[1] == '.') + return 0; /* No - double dot. */ + } + else if (!strchr (ldh_chars, *s)) + return 0; + else if (*s == '-') + { + if (string == s) + return 0; /* Leading hyphen. */ + if (s[-1] == '.') + return 0; /* Hyphen at begin of a label. */ + if (s[1] == '.') + return 0; /* Hyphen at start of a label. */ + if (!s[1]) + return 0; /* Trailing hyphen. */ + } + + return !!*string; +} diff --git a/common/mbox-util.h b/common/mbox-util.h index bce003f..7355cee 100644 --- a/common/mbox-util.h +++ b/common/mbox-util.h @@ -24,6 +24,7 @@ int is_valid_mailbox (const char *name); int is_valid_mailbox_mem (const void *buffer, size_t length); char *mailbox_from_userid (const char *userid); int is_valid_user_id (const char *uid); +int is_valid_domain_name (const char *string); #endif /*GNUPG_COMMON_MBOX_UTIL_H*/ diff --git a/common/t-mbox-util.c b/common/t-mbox-util.c index 979d4b3..fb1ac12 100644 --- a/common/t-mbox-util.c +++ b/common/t-mbox-util.c @@ -33,7 +33,7 @@ static void -run_test (void) +run_mbox_test (void) { static struct { @@ -93,13 +93,64 @@ run_test (void) } +static void +run_dns_test (void) +{ + static struct + { + const char *name; + int valid; + } testtbl[] = + { + { "", 0 }, + { ".", 0 }, + { "-", 0 }, + { "a", 1 }, + { "ab", 1 }, + { "a.b", 1 }, + { "a.b.", 1 }, + { ".a.b.", 0 }, + { ".a.b", 0 }, + { "-a.b", 0 }, + { "a-.b", 0 }, + { "a.-b", 0 }, + { "a.b-", 0 }, + { "a.b-.", 0 }, + { "a..b", 0 }, + { "ab.c", 1 }, + { "a-b.c", 1 }, + { "a-b-.c", 0 }, + { "-a-b.c", 0 }, + { "example.org", 1 }, + { "x.example.org", 1 }, + { "xy.example.org", 1 }, + { "Xy.example.org", 1 }, + { "-Xy.example.org", 0 }, + { "Xy.example-.org", 0 }, + { "foo.example.org..", 0 }, + { "foo.example.org.", 1 }, + { ".foo.example.org.", 0 }, + { "..foo.example.org.", 0 }, + { NULL, 0 } + }; + int idx; + + for (idx=0; testtbl[idx].name; idx++) + { + if (is_valid_domain_name (testtbl[idx].name) != testtbl[idx].valid) + fail (idx); + } +} + + int main (int argc, char **argv) { (void)argc; (void)argv; - run_test (); + run_mbox_test (); + run_dns_test (); return 0; } commit d43248af9242d30e95f58285e4f2a2e927aae937 Author: Ji?? Kereste? Date: Tue Jul 17 17:11:42 2018 +0200 scd: Add support for Trustica Cryptoucan. (cherry picked from commit 967d3649d24aba623133808e8d01675dff389fbb) diff --git a/scd/apdu.c b/scd/apdu.c index cd98cc9..9e3594b 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -964,7 +964,8 @@ pcsc_vendor_specific_init (int slot) else if (strstr (reader_table[slot].rdrname, "cyberJack") || strstr (reader_table[slot].rdrname, "DIGIPASS") || strstr (reader_table[slot].rdrname, "Gnuk") - || strstr (reader_table[slot].rdrname, "KAAN")) + || strstr (reader_table[slot].rdrname, "KAAN") + || strstr (reader_table[slot].rdrname, "Trustica")) reader_table[slot].pinpad_varlen_supported = 1; } @@ -1038,7 +1039,8 @@ pcsc_vendor_specific_init (int slot) else if (vendor == 0x0c4b /* Tested with Reiner cyberJack GO */ || vendor == 0x1a44 /* Tested with Vasco DIGIPASS 920 */ || vendor == 0x234b /* Tested with FSIJ Gnuk Token */ - || vendor == 0x0d46 /* Tested with KAAN Advanced??? */) + || vendor == 0x0d46 /* Tested with KAAN Advanced??? */ + || (vendor == 0x1fc9 && product == 0x81e6) /* Tested with Trustica Cryptoucan */) reader_table[slot].pinpad_varlen_supported = 1; return 0; diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index f33a36c..ae40f01 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -3387,6 +3387,12 @@ ccid_transceive_secure (ccid_driver_t handle, if (handle->id_product != CHERRY_ST2000) cherry_mode = 1; break; + case VENDOR_NXP: + if (handle->id_product == CRYPTOUCAN){ + pininfo->maxlen = 25; + enable_varlen = 1; + } + break; default: if ((handle->id_vendor == VENDOR_GEMPC && handle->id_product == GEMPC_PINPAD) diff --git a/scd/ccid-driver.h b/scd/ccid-driver.h index b6da30c..c31c25f 100644 --- a/scd/ccid-driver.h +++ b/scd/ccid-driver.h @@ -68,7 +68,8 @@ enum { VENDOR_REINER = 0x0c4b, VENDOR_KAAN = 0x0d46, VENDOR_FSIJ = 0x234b, - VENDOR_VASCO = 0x1a44 + VENDOR_VASCO = 0x1a44, + VENDOR_NXP = 0x1fc9, }; @@ -84,6 +85,7 @@ enum { #define GEMPC_CT30 0x3437 #define VEGA_ALPHA 0x0008 #define CYBERJACK_GO 0x0504 +#define CRYPTOUCAN 0x81e6 #endif /*CCID_DRIVER_INCLUDE_USB_IDS*/ ----------------------------------------------------------------------- Summary of changes: common/mbox-util.c | 39 +++++++++++++++++++++++++++++++++++++ common/mbox-util.h | 1 + common/t-mbox-util.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++-- dirmngr/server.c | 12 ++++++++++++ g10/call-dirmngr.c | 10 +++++++++- scd/apdu.c | 6 ++++-- scd/ccid-driver.c | 6 ++++++ scd/ccid-driver.h | 4 +++- 8 files changed, 127 insertions(+), 6 deletions(-) hooks/post-receive -- The GNU Privacy Guard http://git.gnupg.org From cvs at cvs.gnupg.org Mon Jul 30 13:26:21 2018 From: cvs at cvs.gnupg.org (by Maximilian Krambach) Date: Mon, 30 Jul 2018 13:26:21 +0200 Subject: [git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-83-ge16a87e Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, javascript-binding has been updated via e16a87e83910ebb6bfdc4148369165f121f0997e (commit) from 522121ea7e105acc22795b1997ca500c7b227b4f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit e16a87e83910ebb6bfdc4148369165f121f0997e Author: Maximilian Krambach Date: Mon Jul 30 12:31:27 2018 +0200 js: Making objects inmutable -- * An Object.freeze should stop any malicious third party from changing objects' methods once the objects are instantiated (see unittest for an approach that would have worked before) - An initialized gpgmejs- object doesn't have a '_Keyring' property anymore (it still has its 'Keyring') - The internal expect='base64' needed to be turned into a method. diff --git a/lang/js/BrowserTestExtension/tests/startup.js b/lang/js/BrowserTestExtension/tests/startup.js index 1e2784d..63358aa 100644 --- a/lang/js/BrowserTestExtension/tests/startup.js +++ b/lang/js/BrowserTestExtension/tests/startup.js @@ -37,7 +37,6 @@ describe('GPGME context', function(){ context.Keyring = input; expect(context.Keyring).to.be.an('object'); expect(context.Keyring).to.not.equal(input); - expect(context._Keyring).to.equal(context.Keyring); expect(context.Keyring.getKeys).to.be.a('function'); expect(context.Keyring.getDefaultKey).to.be.a('function'); expect(context.Keyring.importKey).to.be.a('function'); diff --git a/lang/js/src/Connection.js b/lang/js/src/Connection.js index 561a5b7..b010575 100644 --- a/lang/js/src/Connection.js +++ b/lang/js/src/Connection.js @@ -118,7 +118,7 @@ export class Connection{ } let chunksize = message.chunksize; return new Promise(function(resolve, reject){ - let answer = new Answer(message); + let answer = Object.freeze(new Answer(message)); let listener = function(msg) { if (!msg){ _connection.onMessage.removeListener(listener); @@ -188,14 +188,15 @@ class Answer{ */ constructor(message){ const operation = message.operation; - const expect = message.expect; + const expected = message.getExpect(); let response_b64 = null; this.getOperation = function(){ return operation; }; + this.getExpect = function(){ - return expect; + return expected; }; /** @@ -260,7 +261,7 @@ class Answer{ } if (_decodedResponse.base64 === true && poa.data[key] === 'string' - && this.getExpect() === undefined + && this.getExpect() !== 'base64' ){ _response[key] = decodeURIComponent( atob(_decodedResponse[key]).split('').map( diff --git a/lang/js/src/Errors.js b/lang/js/src/Errors.js index 0cf1af1..39e3a74 100644 --- a/lang/js/src/Errors.js +++ b/lang/js/src/Errors.js @@ -119,7 +119,7 @@ const err_list = { export function gpgme_error(code = 'GENERIC_ERROR', info){ if (err_list.hasOwnProperty(code)){ if (err_list[code].type === 'error'){ - return new GPGME_Error(code); + return Object.freeze(new GPGME_Error(code)); } if (err_list[code].type === 'warning'){ // eslint-disable-next-line no-console @@ -127,10 +127,10 @@ export function gpgme_error(code = 'GENERIC_ERROR', info){ } return null; } else if (code === 'GNUPG_ERROR'){ - return new GPGME_Error(code, info); + return Object.freeze(new GPGME_Error(code, info)); } else { - return new GPGME_Error('GENERIC_ERROR'); + return Object.freeze(new GPGME_Error('GENERIC_ERROR')); } } diff --git a/lang/js/src/Key.js b/lang/js/src/Key.js index d5873a7..f431a28 100644 --- a/lang/js/src/Key.js +++ b/lang/js/src/Key.js @@ -37,7 +37,7 @@ export function createKey(fingerprint, async = false){ if (!isFingerprint(fingerprint) || typeof(async) !== 'boolean'){ return gpgme_error('PARAM_WRONG'); } - else return new GPGME_Key(fingerprint, async); + else return Object.freeze(new GPGME_Key(fingerprint, async)); } /** @@ -104,15 +104,15 @@ export class GPGME_Key { case 'subkeys': _data.subkeys = []; for (let i=0; i< data.subkeys.length; i++) { - _data.subkeys.push( - new GPGME_Subkey(data.subkeys[i])); + _data.subkeys.push(Object.freeze( + new GPGME_Subkey(data.subkeys[i]))); } break; case 'userids': _data.userids = []; for (let i=0; i< data.userids.length; i++) { - _data.userids.push( - new GPGME_UserId(data.userids[i])); + _data.userids.push(Object.freeze( + new GPGME_UserId(data.userids[i]))); } break; case 'last_update': diff --git a/lang/js/src/Message.js b/lang/js/src/Message.js index c0b6ed5..e2c0734 100644 --- a/lang/js/src/Message.js +++ b/lang/js/src/Message.js @@ -36,7 +36,7 @@ export function createMessage(operation){ return gpgme_error('PARAM_WRONG'); } if (permittedOperations.hasOwnProperty(operation)){ - return new GPGME_Message(operation); + return Object.freeze(new GPGME_Message(operation)); } else { return gpgme_error('MSG_WRONG_OP'); } @@ -56,11 +56,21 @@ export class GPGME_Message { op: operation, chunksize: 1023* 1024 }; + let expected = null; this.getOperation = function(){ return _msg.op; }; + this.setExpect = function(value){ + if (value === 'base64'){ + expected = value; + } + }; + this.getExpect = function(){ + return expected; + }; + /** * The maximum size of responses from gpgme in bytes. As of July 2018, * most browsers will only accept answers up to 1 MB of size. @@ -204,7 +214,7 @@ export class GPGME_Message { return new Promise(function(resolve, reject) { if (me.isComplete() === true) { - let conn = new Connection; + let conn = Object.freeze(new Connection); conn.post(me).then(function(response) { resolve(response); }, function(reason) { diff --git a/lang/js/src/Signature.js b/lang/js/src/Signature.js index 0ee58e9..55131b0 100644 --- a/lang/js/src/Signature.js +++ b/lang/js/src/Signature.js @@ -66,7 +66,7 @@ export function createSignature(sigObject){ } } } - return new GPGME_Signature(sigObject); + return Object.freeze(new GPGME_Signature(sigObject)); } diff --git a/lang/js/src/gpgmejs.js b/lang/js/src/gpgmejs.js index 720490d..9154979 100644 --- a/lang/js/src/gpgmejs.js +++ b/lang/js/src/gpgmejs.js @@ -102,7 +102,7 @@ export class GpgME { */ this.getKeyring = function(){ if (!_Keyring){ - _Keyring = new GPGME_Keyring; + _Keyring = Object.freeze(new GPGME_Keyring); } return _Keyring; }; @@ -241,7 +241,7 @@ export class GpgME { putData(msg, data); return new Promise(function(resolve,reject) { if (mode ==='detached'){ - msg.expect= 'base64'; + msg.setExpect('base64'); } msg.post().then( function(message) { if (mode === 'clearsign'){ @@ -319,10 +319,7 @@ export class GpgME { * Accesses the {@link GPGME_Keyring}. */ get Keyring(){ - if (!this._Keyring){ - this._Keyring = new GPGME_Keyring; - } - return this._Keyring; + return this.getKeyring(); } } diff --git a/lang/js/src/index.js b/lang/js/src/index.js index dc613fc..2fed95f 100644 --- a/lang/js/src/index.js +++ b/lang/js/src/index.js @@ -34,11 +34,11 @@ import { Connection } from './Connection'; */ function init(){ return new Promise(function(resolve, reject){ - let connection = new Connection; + let connection = Object.freeze(new Connection); connection.checkConnection(false).then( function(result){ if (result === true) { - resolve(new GpgME()); + resolve(Object.freeze(new GpgME())); } else { reject(gpgme_error('CONN_NO_CONNECT')); } diff --git a/lang/js/unittests.js b/lang/js/unittests.js index 6228993..3304b1e 100644 --- a/lang/js/unittests.js +++ b/lang/js/unittests.js @@ -253,6 +253,22 @@ function unittests (){ expect(key.fingerprint.code).to.equal('KEY_INVALID'); } }); + + it('Overwriting getFingerprint does not work', function(){ + const evilFunction = function(){ + return 'bad Data'; + }; + let key = createKey(kp.validKeyFingerprint, true); + expect(key.fingerprint).to.equal(kp.validKeyFingerprint); + try { + key.getFingerprint = evilFunction; + } + catch(e) { + expect(e).to.be.an.instanceof(TypeError); + } + expect(key.fingerprint).to.equal(kp.validKeyFingerprint); + expect(key.getFingerprint).to.not.equal(evilFunction); + }); // TODO: tests for subkeys // TODO: tests for userids // TODO: some invalid tests for key/keyring ----------------------------------------------------------------------- Summary of changes: lang/js/BrowserTestExtension/tests/startup.js | 1 - lang/js/src/Connection.js | 9 +++++---- lang/js/src/Errors.js | 6 +++--- lang/js/src/Key.js | 10 +++++----- lang/js/src/Message.js | 14 ++++++++++++-- lang/js/src/Signature.js | 2 +- lang/js/src/gpgmejs.js | 9 +++------ lang/js/src/index.js | 4 ++-- lang/js/unittests.js | 16 ++++++++++++++++ 9 files changed, 47 insertions(+), 24 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 31 16:55:22 2018 From: cvs at cvs.gnupg.org (by Maximilian Krambach) Date: Tue, 31 Jul 2018 16:55:22 +0200 Subject: [git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-84-g9d247b7 Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, javascript-binding has been updated via 9d247b7fd5edd11fb5710a057baec671276f5034 (commit) from e16a87e83910ebb6bfdc4148369165f121f0997e (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 9d247b7fd5edd11fb5710a057baec671276f5034 Author: Maximilian Krambach Date: Tue Jul 31 16:54:43 2018 +0200 js: Fix Key.hasSecret answer -- * The comparision result between Keyring and Keyring with secrets was set to the wrong Object which was not returned at all. diff --git a/lang/js/src/Key.js b/lang/js/src/Key.js index f431a28..88c49d3 100644 --- a/lang/js/src/Key.js +++ b/lang/js/src/Key.js @@ -74,7 +74,7 @@ export class GPGME_Key { * @returns {Boolean} If the Key has a secret subkey. */ this.hasSecret= function (){ - return this.get('hasSecret', true); + return this.get('hasSecret'); }; /** diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index 31c4f92..8715a47 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -46,7 +46,7 @@ export class GPGME_Keyring { * resort to a refresh() first. * @param {Boolean} search (optional) retrieve Keys from external * servers with the method(s) defined in gnupg (e.g. WKD/HKP lookup) - * @returns {Promise.|GPGME_Error>} + * @returns {Promise>} * @static * @async */ @@ -79,9 +79,9 @@ export class GPGME_Keyring { }; } secondrequest().then(function(answer) { - for (let i=0; i < result.keys.length; i++){ + for (let i=0; i < answer.keys.length; i++){ if (prepare_sync === true){ - result.keys[i].hasSecret = false; + result.keys[i].hasSecret = undefined; if (answer && answer.keys) { for (let j=0; j < answer.keys.length; j++ ){ @@ -91,7 +91,9 @@ export class GPGME_Keyring { a.fingerprint === b.fingerprint ) { if (a.secret === true){ - a.hasSecret = true; + b.hasSecret = true; + } else { + b.hasSecret = false; } break; } ----------------------------------------------------------------------- Summary of changes: lang/js/src/Key.js | 2 +- lang/js/src/Keyring.js | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org From cvs at cvs.gnupg.org Tue Jul 31 17:36:57 2018 From: cvs at cvs.gnupg.org (by Maximilian Krambach) Date: Tue, 31 Jul 2018 17:36:57 +0200 Subject: [git] GPGME - branch, javascript-binding, updated. gpgme-1.11.1-85-g6313a2d Message-ID: This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GnuPG Made Easy". The branch, javascript-binding has been updated via 6313a2de9ee84a9321292f775e4d6c790486d3dc (commit) from 9d247b7fd5edd11fb5710a057baec671276f5034 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 6313a2de9ee84a9321292f775e4d6c790486d3dc Author: Maximilian Krambach Date: Tue Jul 31 17:35:52 2018 +0200 js: fix confusion about loop in last commit -- * The aim is to iterate through the results of the first request (all keys), and then add the propert 'hasSecret' to those that are in the second request (secret Keysring) as well. I messed this up in a recent change, and it escaped testing. diff --git a/lang/js/src/Keyring.js b/lang/js/src/Keyring.js index 8715a47..d25216c 100644 --- a/lang/js/src/Keyring.js +++ b/lang/js/src/Keyring.js @@ -79,9 +79,8 @@ export class GPGME_Keyring { }; } secondrequest().then(function(answer) { - for (let i=0; i < answer.keys.length; i++){ + for (let i=0; i < result.keys.length; i++){ if (prepare_sync === true){ - result.keys[i].hasSecret = undefined; if (answer && answer.keys) { for (let j=0; j < answer.keys.length; j++ ){ ----------------------------------------------------------------------- Summary of changes: lang/js/src/Keyring.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) hooks/post-receive -- GnuPG Made Easy http://git.gnupg.org