summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDongHun Kwak <dh0128.kwak@samsung.com>2021-02-09 16:00:45 +0900
committerDongHun Kwak <dh0128.kwak@samsung.com>2021-02-09 16:00:45 +0900
commite299a90138c4ee04892f06ea99394c0f55d311db (patch)
treec54132a01468497d3973c2e3053ca1ee258c855e
parentc8351206466f4f5ac3feb7ad2e5457337b9593ad (diff)
downloadgpg2-upstream/2.2.15.tar.gz
gpg2-upstream/2.2.15.tar.bz2
gpg2-upstream/2.2.15.zip
Imported Upstream version 2.2.15upstream/2.2.15
-rw-r--r--NEWS21
-rw-r--r--agent/command.c24
-rw-r--r--configure.ac2
-rw-r--r--dirmngr/dns.c80
-rw-r--r--doc/gpg.texi6
-rw-r--r--doc/wks.texi8
-rw-r--r--sm/gpgsm.c19
-rw-r--r--tools/gpg-wks-client.c100
-rw-r--r--tools/gpg-wks-server.c2
-rw-r--r--tools/gpg-wks.h4
-rw-r--r--tools/wks-util.c72
11 files changed, 277 insertions, 61 deletions
diff --git a/NEWS b/NEWS
index 8c55318..adf61db 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,24 @@
+Noteworthy changes in version 2.2.15 (2019-03-26)
+-------------------------------------------------
+
+ * sm: Fix --logger-fd and --status-fd on Windows for non-standard
+ file descriptors.
+
+ * sm: Allow decryption even if expired keys are configured. [#4431]
+
+ * agent: Change command KEYINFO to print ssh fingerprints with other
+ hash algos.
+
+ * dirmngr: Fix build problems on Solaris due to the use of reserved
+ symbol names. [#4420]
+
+ * wkd: New commands --print-wkd-hash and --print-wkd-url for
+ gpg-wks-client.
+
+ Release-info: https://dev.gnupg.org/T4434
+ See-also: gnupg-announce/2019q1/000436.html
+
+
Noteworthy changes in version 2.2.14 (2019-03-19)
-------------------------------------------------
diff --git a/agent/command.c b/agent/command.c
index f804178..4839ffe 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -1048,7 +1048,7 @@ cmd_readkey (assuan_context_t ctx, char *line)
static const char hlp_keyinfo[] =
- "KEYINFO [--[ssh-]list] [--data] [--ssh-fpr] [--with-ssh] <keygrip>\n"
+ "KEYINFO [--[ssh-]list] [--data] [--ssh-fpr[=algo]] [--with-ssh] <keygrip>\n"
"\n"
"Return information about the key specified by the KEYGRIP. If the\n"
"key is not available GPG_ERR_NOT_FOUND is returned. If the option\n"
@@ -1084,7 +1084,9 @@ static const char hlp_keyinfo[] =
" '-' - Unknown protection.\n"
"\n"
"FPR returns the formatted ssh-style fingerprint of the key. It is only\n"
- " printed if the option --ssh-fpr has been used. It defaults to '-'.\n"
+ " printed if the option --ssh-fpr has been used. If ALGO is not given\n"
+ " to that option the default ssh fingerprint algo is used. Without the\n"
+ " option a '-' is printed.\n"
"\n"
"TTL is the TTL in seconds for that key or '-' if n/a.\n"
"\n"
@@ -1171,7 +1173,7 @@ do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx,
if (!agent_raw_key_from_file (ctrl, grip, &key))
{
- ssh_get_fingerprint_string (key, GCRY_MD_MD5, &fpr);
+ ssh_get_fingerprint_string (key, with_ssh_fpr, &fpr);
gcry_sexp_release (key);
}
}
@@ -1252,7 +1254,21 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
else
list_mode = has_option (line, "--list");
opt_data = has_option (line, "--data");
- opt_ssh_fpr = has_option (line, "--ssh-fpr");
+
+ if (has_option_name (line, "--ssh-fpr"))
+ {
+ if (has_option (line, "--ssh-fpr=md5"))
+ opt_ssh_fpr = GCRY_MD_MD5;
+ else if (has_option (line, "--ssh-fpr=sha1"))
+ opt_ssh_fpr = GCRY_MD_SHA1;
+ else if (has_option (line, "--ssh-fpr=sha256"))
+ opt_ssh_fpr = GCRY_MD_SHA256;
+ else
+ opt_ssh_fpr = opt.ssh_fingerprint_digest;
+ }
+ else
+ opt_ssh_fpr = 0;
+
opt_with_ssh = has_option (line, "--with-ssh");
line = skip_options (line);
diff --git a/configure.ac b/configure.ac
index 9260684..7951bd2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -28,7 +28,7 @@ min_automake_version="1.14"
m4_define([mym4_package],[gnupg])
m4_define([mym4_major], [2])
m4_define([mym4_minor], [2])
-m4_define([mym4_micro], [14])
+m4_define([mym4_micro], [15])
# To start a new development series, i.e a new major or minor number
# you need to mark an arbitrary commit before the first beta release
diff --git a/dirmngr/dns.c b/dirmngr/dns.c
index 14aab24..4c3b559 100644
--- a/dirmngr/dns.c
+++ b/dirmngr/dns.c
@@ -2217,8 +2217,8 @@ static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) {
void dns_p_dump(struct dns_packet *P, FILE *fp) {
- struct dns_rr_i _I = { 0 };
- dns_p_dump3(P, &_I, fp);
+ struct dns_rr_i I_instance = { 0 };
+ dns_p_dump3(P, &I_instance, fp);
} /* dns_p_dump() */
@@ -5275,8 +5275,8 @@ error:
struct dns_packet *dns_hosts_query(struct dns_hosts *hosts, struct dns_packet *Q, int *error_) {
- union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
- struct dns_packet *P = dns_p_init(&_P.p, 512);
+ union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } P_instance = { 0 };
+ struct dns_packet *P = dns_p_init(&P_instance.p, 512);
struct dns_packet *A = 0;
struct dns_rr rr;
struct dns_hosts_entry *ent;
@@ -6837,7 +6837,7 @@ unsigned dns_hints_grep(struct sockaddr **sa, socklen_t *sa_len, unsigned lim, s
struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q, int *error_) {
- union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
+ union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } P_instance = { 0 };
struct dns_packet *A, *P;
struct dns_rr rr;
char zone[DNS_D_MAXNAME + 1];
@@ -6846,11 +6846,11 @@ struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q
struct sockaddr *sa;
socklen_t slen;
int error;
- struct dns_rr_i _I = { 0 };
+ struct dns_rr_i I_instance = { 0 };
- _I.section = DNS_S_QUESTION;
+ I_instance.section = DNS_S_QUESTION;
- if (!dns_rr_grep(&rr, 1, &_I, Q, &error))
+ if (!dns_rr_grep(&rr, 1, &I_instance, Q, &error))
goto error;
if (!(zlen = dns_d_expand(zone, sizeof zone, rr.dn.p, Q, &error)))
@@ -6858,7 +6858,7 @@ struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q
else if (zlen >= sizeof zone)
goto toolong;
- P = dns_p_init(&_P.p, 512);
+ P = dns_p_init(&P_instance.p, 512);
dns_header(P)->qr = 1;
if ((error = dns_rr_copy(P, &rr, Q)))
@@ -8463,8 +8463,8 @@ error:
static struct dns_packet *dns_res_glue(struct dns_resolver *R, struct dns_packet *Q) {
- union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
- struct dns_packet *P = dns_p_init(&_P.p, 512);
+ union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } P_instance = { 0 };
+ struct dns_packet *P = dns_p_init(&P_instance.p, 512);
char qname[DNS_D_MAXNAME + 1];
size_t qlen;
enum dns_type qtype;
@@ -8537,20 +8537,20 @@ static int dns_res_nameserv_cmp(struct dns_rr *a, struct dns_rr *b, struct dns_r
int cmp, error;
if (!(error = dns_ns_parse(&ns, a, P))) {
- struct dns_rr_i _I = { 0 };
+ struct dns_rr_i I_instance = { 0 };
- _I.section = (DNS_S_ALL & ~DNS_S_QD);
- _I.name = ns.host;
- _I.type = DNS_T_A;
- glued[0] = !!dns_rr_grep(&x, 1, &_I, P, &error);
+ I_instance.section = (DNS_S_ALL & ~DNS_S_QD);
+ I_instance.name = ns.host;
+ I_instance.type = DNS_T_A;
+ glued[0] = !!dns_rr_grep(&x, 1, &I_instance, P, &error);
}
if (!(error = dns_ns_parse(&ns, b, P))) {
- struct dns_rr_i _I = { 0 };
+ struct dns_rr_i I_instance = { 0 };
- _I.section = (DNS_S_ALL & ~DNS_S_QD);
- _I.name = ns.host;
- _I.type = DNS_T_A;
- glued[1] = !!dns_rr_grep(&y, 1, &_I, P, &error);
+ I_instance.section = (DNS_S_ALL & ~DNS_S_QD);
+ I_instance.name = ns.host;
+ I_instance.type = DNS_T_A;
+ glued[1] = !!dns_rr_grep(&y, 1, &I_instance, P, &error);
}
if ((cmp = glued[1] - glued[0])) {
return cmp;
@@ -9916,13 +9916,13 @@ exec:
return dns_ai_setent(ent, &any, rr.type, ai);
case DNS_AI_S_SUBMIT_G:
{
- struct dns_rr_i _I = { 0 };
+ struct dns_rr_i I_instance = { 0 };
- _I.section = DNS_S_QD;
- _I.name = ai->g.name;
- _I.type = ai->g.type;
+ I_instance.section = DNS_S_QD;
+ I_instance.name = ai->g.name;
+ I_instance.type = ai->g.type;
/* skip if already queried */
- if (dns_rr_grep(&rr, 1, &_I, ai->glue, &error))
+ if (dns_rr_grep(&rr, 1, &I_instance, ai->glue, &error))
dns_ai_goto(DNS_AI_S_FOREACH_I);
/* skip if we recursed (CNAME chains should have been handled in the resolver) */
if (++ai->g_depth > 1)
@@ -10598,7 +10598,7 @@ static struct dns_trace *trace(const char *mode) {
static void print_packet(struct dns_packet *P, FILE *fp) {
- struct dns_rr_i _I = { 0 };
+ struct dns_rr_i I_instance = { 0 };
I.sort = MAIN.sort;
dns_p_dump3(P, &I, fp);
@@ -10608,10 +10608,10 @@ static void print_packet(struct dns_packet *P, FILE *fp) {
static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
- union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
- union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _Q = { 0 };
- struct dns_packet *P = dns_p_init(&_P.p, 512);
- struct dns_packet *Q = dns_p_init(&_Q.p, 512);
+ union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } P_instance = { 0 };
+ union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } Q_instance = { 0 };
+ struct dns_packet *P = dns_p_init(&P_instance.p, 512);
+ struct dns_packet *Q = dns_p_init(&Q_instance.p, 512);
enum dns_section section;
struct dns_rr rr;
int error;
@@ -10655,7 +10655,7 @@ static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
const char *dn = "ns8.yahoo.com";
char *_name = dns_d_init(_p, sizeof _p, dn, strlen (dn), DNS_D_ANCHOR);
struct dns_rr rrset[32];
- struct dns_rr_i _I = { 0 };
+ struct dns_rr_i I_instance = { 0 };
struct dns_rr_i *rri = &I;
unsigned rrcount = dns_rr_grep(rrset, lengthof(rrset), rri, Q, &error);
@@ -10818,8 +10818,8 @@ static int show_hosts(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
static int query_hosts(int argc, char *argv[]) {
- union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _Q = { 0 };
- struct dns_packet *Q = dns_p_init(&_Q.p, 512);
+ union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } Q_instance = { 0 };
+ struct dns_packet *Q = dns_p_init(&Q_instance.p, 512);
struct dns_packet *A;
char qname[DNS_D_MAXNAME + 1];
size_t qlen;
@@ -10937,8 +10937,8 @@ static int dump_random(int argc, char *argv[]) {
static int send_query(int argc, char *argv[]) {
- union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _Q = { 0 };
- struct dns_packet *A, *Q = dns_p_init(&_Q.p, 512);
+ union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } Q_instance = { 0 };
+ struct dns_packet *A, *Q = dns_p_init(&Q_instance.p, 512);
char host[INET6_ADDRSTRLEN + 1];
struct sockaddr_storage ss;
struct dns_socket *so;
@@ -11033,10 +11033,10 @@ static int show_hints(int argc, char *argv[]) {
if (0 == strcmp(how, "plain")) {
dns_hints_dump(hints, stdout);
} else {
- union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
+ union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } P_instance = { 0 };
struct dns_packet *query, *answer;
- query = dns_p_init(&_P.p, 512);
+ query = dns_p_init(&P_instance.p, 512);
if ((error = dns_p_push(query, DNS_S_QUESTION, who, strlen(who), DNS_T_A, DNS_C_IN, 0, 0)))
panic("%s: %s", who, dns_strerror(error));
@@ -11199,8 +11199,8 @@ static int echo_port(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
panic("127.0.0.1:5353: %s", dns_strerror(errno));
for (;;) {
- union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
- struct dns_packet *pkt = dns_p_init(&_P.p, 512);
+ union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } P_instance = { 0 };
+ struct dns_packet *pkt = dns_p_init(&P_instance.p, 512);
struct sockaddr_storage ss;
socklen_t slen = sizeof ss;
ssize_t count;
diff --git a/doc/gpg.texi b/doc/gpg.texi
index 1597f9e..22813c7 100644
--- a/doc/gpg.texi
+++ b/doc/gpg.texi
@@ -2320,7 +2320,8 @@ opposite meaning. The options are:
on the keyring. This option is the same as running the @option{--edit-key}
command "clean" after import. Defaults to no.
- @item repair-keys. After import, fix various problems with the
+ @item repair-keys
+ After import, fix various problems with the
keys. For example, this reorders signatures, and strips duplicate
signatures. Defaults to yes.
@@ -3229,7 +3230,8 @@ secret keyrings.
@item --no-keyring
@opindex no-keyring
-Do not add use any keyrings even if specified as options.
+Do not use any keyring at all. This overrides the default and all
+options which specify keyrings.
@item --skip-verify
@opindex skip-verify
diff --git a/doc/wks.texi b/doc/wks.texi
index 7a19e75..2fa3c24 100644
--- a/doc/wks.texi
+++ b/doc/wks.texi
@@ -101,6 +101,14 @@ fingerprint and the mailbox separated by a space. The command
@option{--remove-key} removes a key from that directory, its only
argument is a user-id.
+The command @option{--print-wkd-hash} prints the WKD user-id identifiers
+and the corresponding mailboxes from the user-ids given on the command
+line or via stdin (one user-id per line).
+
+The command @option{--print-wkd-url} prints the URLs used to fetch the
+key for the given user-ids from WKD. The meanwhile preferred format
+with sub-domains is used here.
+
@command{gpg-wks-client} is not commonly invoked directly and thus it
is not installed in the bin directory. Here is an example how it can
be invoked manually to check for a Web Key Directory entry for
diff --git a/sm/gpgsm.c b/sm/gpgsm.c
index 52f26e2..a01a7c8 100644
--- a/sm/gpgsm.c
+++ b/sm/gpgsm.c
@@ -1281,8 +1281,12 @@ main ( int argc, char **argv)
case oDebugNoChainValidation: opt.no_chain_validation = 1; break;
case oDebugIgnoreExpiration: opt.ignore_expiration = 1; break;
- case oStatusFD: ctrl.status_fd = pargs.r.ret_int; break;
- case oLoggerFD: log_set_fd (pargs.r.ret_int ); break;
+ case oStatusFD:
+ ctrl.status_fd = translate_sys2libc_fd_int (pargs.r.ret_int, 1);
+ break;
+ case oLoggerFD:
+ log_set_fd (translate_sys2libc_fd_int (pargs.r.ret_int, 1));
+ break;
case oWithMD5Fingerprint:
opt.with_md5_fingerprint=1; /*fall through*/
case oWithFingerprint:
@@ -1732,6 +1736,8 @@ main ( int argc, char **argv)
if (!do_not_setup_keys)
{
+ int errcount = log_get_errorcount (0);
+
for (sl = locusr; sl ; sl = sl->next)
{
int rc = gpgsm_add_to_certlist (&ctrl, sl->d, 1, &signerlist, 0);
@@ -1760,6 +1766,15 @@ main ( int argc, char **argv)
if ((sl->flags & 1))
do_add_recipient (&ctrl, sl->d, &recplist, 1, recp_required);
}
+
+ /* We do not require a recipient for decryption but because
+ * recipients and signers are always checked and log_error is
+ * sometimes used (for failed signing keys or due to a failed
+ * CRL checking) that would have bumbed up the error counter.
+ * We clear the counter in the decryption case because there is
+ * no reason to force decryption to fail. */
+ if (cmd == aDecrypt && !errcount)
+ log_get_errorcount (1); /* clear counter */
}
if (log_get_errorcount(0))
diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c
index 78e4fe4..050c8aa 100644
--- a/tools/gpg-wks-client.c
+++ b/tools/gpg-wks-client.c
@@ -61,6 +61,8 @@ enum cmd_and_opt_values
aRead,
aInstallKey,
aRemoveKey,
+ aPrintWKDHash,
+ aPrintWKDURL,
oGpgProgram,
oSend,
@@ -90,6 +92,10 @@ static ARGPARSE_OPTS opts[] = {
"install a key into a directory"),
ARGPARSE_c (aRemoveKey, "remove-key",
"remove a key from a directory"),
+ ARGPARSE_c (aPrintWKDHash, "print-wkd-hash",
+ "Print the WKD identifier for the given user ids"),
+ ARGPARSE_c (aPrintWKDURL, "print-wkd-url",
+ "Print the WKD URL for the given user id"),
ARGPARSE_group (301, ("@\nOptions:\n ")),
@@ -129,6 +135,8 @@ const char *fake_submission_addr;
static void wrong_args (const char *text) GPGRT_ATTR_NORETURN;
+static gpg_error_t proc_userid_from_stdin (gpg_error_t (*func)(const char *),
+ const char *text);
static gpg_error_t command_supported (char *userid);
static gpg_error_t command_check (char *userid);
static gpg_error_t command_send (const char *fingerprint, const char *userid);
@@ -230,6 +238,8 @@ parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
case aCheck:
case aInstallKey:
case aRemoveKey:
+ case aPrintWKDHash:
+ case aPrintWKDURL:
cmd = pargs->r_opt;
break;
@@ -246,7 +256,7 @@ parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
int
main (int argc, char **argv)
{
- gpg_error_t err;
+ gpg_error_t err, delayed_err;
ARGPARSE_ARGS pargs;
enum cmd_and_opt_values cmd;
@@ -377,6 +387,39 @@ main (int argc, char **argv)
err = wks_cmd_remove_key (*argv);
break;
+ case aPrintWKDHash:
+ case aPrintWKDURL:
+ if (!argc)
+ {
+ if (cmd == aPrintWKDHash)
+ err = proc_userid_from_stdin (wks_cmd_print_wkd_hash,
+ "printing WKD hash");
+ else
+ err = proc_userid_from_stdin (wks_cmd_print_wkd_url,
+ "printing WKD URL");
+ }
+ else
+ {
+ for (err = delayed_err = 0; !err && argc; argc--, argv++)
+ {
+ if (cmd == aPrintWKDHash)
+ err = wks_cmd_print_wkd_hash (*argv);
+ else
+ err = wks_cmd_print_wkd_url (*argv);
+ if (gpg_err_code (err) == GPG_ERR_INV_USER_ID)
+ {
+ /* Diagnostic already printed. */
+ delayed_err = err;
+ err = 0;
+ }
+ else if (err)
+ log_error ("printing hash failed: %s\n", gpg_strerror (err));
+ }
+ if (!err)
+ err = delayed_err;
+ }
+ break;
+
default:
usage (1);
err = 0;
@@ -390,10 +433,63 @@ main (int argc, char **argv)
wks_write_status (STATUS_FAILURE, "- %u", GPG_ERR_GENERAL);
else
wks_write_status (STATUS_SUCCESS, NULL);
- return log_get_errorcount (0)? 1:0;
+ return (err || log_get_errorcount (0))? 1:0;
+}
+
+
+/* Read user ids from stdin and call FUNC for each user id. TEXT is
+ * used for error messages. */
+static gpg_error_t
+proc_userid_from_stdin (gpg_error_t (*func)(const char *), const char *text)
+{
+ gpg_error_t err = 0;
+ gpg_error_t delayed_err = 0;
+ char line[2048];
+ size_t n = 0;
+
+ /* If we are on a terminal disable buffering to get direct response. */
+ if (gnupg_isatty (es_fileno (es_stdin))
+ && gnupg_isatty (es_fileno (es_stdout)))
+ {
+ es_setvbuf (es_stdin, NULL, _IONBF, 0);
+ es_setvbuf (es_stdout, NULL, _IOLBF, 0);
+ }
+
+ while (es_fgets (line, sizeof line - 1, es_stdin))
+ {
+ n = strlen (line);
+ if (!n || line[n-1] != '\n')
+ {
+ err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG
+ : GPG_ERR_INCOMPLETE_LINE);
+ log_error ("error reading stdin: %s\n", gpg_strerror (err));
+ break;
+ }
+ trim_spaces (line);
+ err = func (line);
+ if (gpg_err_code (err) == GPG_ERR_INV_USER_ID)
+ {
+ delayed_err = err;
+ err = 0;
+ }
+ else if (err)
+ log_error ("%s failed: %s\n", text, gpg_strerror (err));
+ }
+ if (es_ferror (es_stdin))
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("error reading stdin: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+
+ leave:
+ if (!err)
+ err = delayed_err;
+ return err;
}
+
/* Add the user id UID to the key identified by FINGERPRINT. */
static gpg_error_t
diff --git a/tools/gpg-wks-server.c b/tools/gpg-wks-server.c
index f83ef65..2082fb8 100644
--- a/tools/gpg-wks-server.c
+++ b/tools/gpg-wks-server.c
@@ -1939,7 +1939,7 @@ command_check_key (const char *userid)
char *addrspec = NULL;
char *fname = NULL;
- err = wks_fname_from_userid (userid, &fname, &addrspec);
+ err = wks_fname_from_userid (userid, 0, &fname, &addrspec);
if (err)
goto leave;
diff --git a/tools/gpg-wks.h b/tools/gpg-wks.h
index e369430..9acd7c3 100644
--- a/tools/gpg-wks.h
+++ b/tools/gpg-wks.h
@@ -98,11 +98,13 @@ gpg_error_t wks_parse_policy (policy_flags_t flags, estream_t stream,
int ignore_unknown);
void wks_free_policy (policy_flags_t policy);
-gpg_error_t wks_fname_from_userid (const char *userid,
+gpg_error_t wks_fname_from_userid (const char *userid, int hash_only,
char **r_fname, char **r_addrspec);
gpg_error_t wks_compute_hu_fname (char **r_fname, const char *addrspec);
gpg_error_t wks_cmd_install_key (const char *fname, const char *userid);
gpg_error_t wks_cmd_remove_key (const char *userid);
+gpg_error_t wks_cmd_print_wkd_hash (const char *userid);
+gpg_error_t wks_cmd_print_wkd_url (const char *userid);
/*-- wks-receive.c --*/
diff --git a/tools/wks-util.c b/tools/wks-util.c
index 3e48709..29e9248 100644
--- a/tools/wks-util.c
+++ b/tools/wks-util.c
@@ -749,9 +749,12 @@ write_to_file (estream_t src, const char *fname)
/* Return the filename and optionally the addrspec for USERID at
- * R_FNAME and R_ADDRSPEC. R_ADDRSPEC might also be set on error. */
+ * R_FNAME and R_ADDRSPEC. R_ADDRSPEC might also be set on error. If
+ * HASH_ONLY is set only the has is returned at R_FNAME and no file is
+ * created. */
gpg_error_t
-wks_fname_from_userid (const char *userid, char **r_fname, char **r_addrspec)
+wks_fname_from_userid (const char *userid, int hash_only,
+ char **r_fname, char **r_addrspec)
{
gpg_error_t err;
char *addrspec = NULL;
@@ -767,7 +770,7 @@ wks_fname_from_userid (const char *userid, char **r_fname, char **r_addrspec)
addrspec = mailbox_from_userid (userid);
if (!addrspec)
{
- if (opt.verbose)
+ if (opt.verbose || hash_only)
log_info ("\"%s\" is not a proper mail address\n", userid);
err = gpg_error (GPG_ERR_INV_USER_ID);
goto leave;
@@ -788,11 +791,20 @@ wks_fname_from_userid (const char *userid, char **r_fname, char **r_addrspec)
goto leave;
}
- *r_fname = make_filename_try (opt.directory, domain, "hu", hash, NULL);
- if (!*r_fname)
- err = gpg_error_from_syserror ();
+ if (hash_only)
+ {
+ *r_fname = hash;
+ hash = NULL;
+ err = 0;
+ }
else
- err = 0;
+ {
+ *r_fname = make_filename_try (opt.directory, domain, "hu", hash, NULL);
+ if (!*r_fname)
+ err = gpg_error_from_syserror ();
+ else
+ err = 0;
+ }
leave:
if (r_addrspec && addrspec)
@@ -1062,7 +1074,7 @@ wks_cmd_remove_key (const char *userid)
char *addrspec = NULL;
char *fname = NULL;
- err = wks_fname_from_userid (userid, &fname, &addrspec);
+ err = wks_fname_from_userid (userid, 0, &fname, &addrspec);
if (err)
goto leave;
@@ -1090,3 +1102,47 @@ wks_cmd_remove_key (const char *userid)
xfree (addrspec);
return err;
}
+
+
+/* Print the WKD hash for the user id to stdout. */
+gpg_error_t
+wks_cmd_print_wkd_hash (const char *userid)
+{
+ gpg_error_t err;
+ char *addrspec, *fname;
+
+ err = wks_fname_from_userid (userid, 1, &fname, &addrspec);
+ if (err)
+ return err;
+
+ es_printf ("%s %s\n", fname, addrspec);
+
+ xfree (fname);
+ xfree (addrspec);
+ return err;
+}
+
+
+/* Print the WKD URL for the user id to stdout. */
+gpg_error_t
+wks_cmd_print_wkd_url (const char *userid)
+{
+ gpg_error_t err;
+ char *addrspec, *fname;
+ char *domain;
+
+ err = wks_fname_from_userid (userid, 1, &fname, &addrspec);
+ if (err)
+ return err;
+
+ domain = strchr (addrspec, '@');
+ if (domain)
+ *domain++ = 0;
+
+ es_printf ("https://openpgpkey.%s/.well-known/openpgpkey/%s/hu/%s?l=%s\n",
+ domain, domain, fname, addrspec);
+
+ xfree (fname);
+ xfree (addrspec);
+ return err;
+}