dirmngr: Support the new WKD draft with the openpgpkey subdomain.
authorWerner Koch <wk@gnupg.org>
Tue, 13 Nov 2018 10:35:39 +0000 (11:35 +0100)
committerWerner Koch <wk@gnupg.org>
Tue, 13 Nov 2018 10:35:39 +0000 (11:35 +0100)
* dirmngr/server.c (proc_wkd_get): Implement new openpgpkey subdomain
method.

Signed-off-by: Werner Koch <wk@gnupg.org>
dirmngr/dns-stuff.c
dirmngr/domaininfo.c
dirmngr/server.c

index f86ccb0..7aa07c7 100644 (file)
@@ -1056,16 +1056,17 @@ resolve_name_standard (ctrl_t ctrl, const char *name, unsigned short port,
 
 
 /* This a wrapper around getaddrinfo with slightly different semantics.
-   NAME is the name to resolve.
-   PORT is the requested port or 0.
-   WANT_FAMILY is either 0 (AF_UNSPEC), AF_INET6, or AF_INET4.
-   WANT_SOCKETTYPE is either SOCK_STREAM or SOCK_DGRAM.
-
-   On success the result is stored in a linked list with the head
-   stored at the address R_AI; the caller must call gpg_addrinfo_free
-   on this.  If R_CANONNAME is not NULL the official name of the host
-   is stored there as a malloced string; if that name is not available
-   NULL is stored.  */
+ * NAME is the name to resolve.
+ * PORT is the requested port or 0.
+ * WANT_FAMILY is either 0 (AF_UNSPEC), AF_INET6, or AF_INET4.
+ * WANT_SOCKETTYPE is either 0 for any socket type
+ *                 or SOCK_STREAM or SOCK_DGRAM.
+ *
+ * On success the result is stored in a linked list with the head
+ * stored at the address R_AI; the caller must call free_dns_addrinfo
+ * on this.  If R_CANONNAME is not NULL the official name of the host
+ * is stored there as a malloced string; if that name is not available
+ * NULL is stored.  */
 gpg_error_t
 resolve_dns_name (ctrl_t ctrl, const char *name, unsigned short port,
                   int want_family, int want_socktype,
index a2effff..f6263b0 100644 (file)
@@ -119,7 +119,7 @@ domaininfo_print_stats (void)
 }
 
 
-/* Return true if DOMAIN definitely does not support WKD.  Noet that
+/* Return true if DOMAIN definitely does not support WKD.  Note that
  * DOMAIN is expected to be lowercase.  */
 int
 domaininfo_is_wkd_not_supported (const char *domain)
index ac25620..4a24253 100644 (file)
@@ -837,8 +837,11 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
   gpg_error_t err = 0;
   char *mbox = NULL;
   char *domainbuf = NULL;
-  char *domain;     /* Points to mbox or domainbuf.  */
-  char *domain_orig;/* Points to mbox.  */
+  char *domain;     /* Points to mbox or domainbuf.  This is used to
+                     * connect to the host.  */
+  char *domain_orig;/* Points to mbox.  This is the used for the
+                     * query; i.e. the domain part of the
+                     * addrspec.  */
   char sha1buf[20];
   char *uri = NULL;
   char *encodedhash = NULL;
@@ -847,6 +850,7 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
   int is_wkd_query;   /* True if this is a real WKD query.  */
   int no_log = 0;
   char portstr[20] = { 0 };
+  int subdomain_mode = 0;
 
   opt_submission_addr = has_option (line, "--submission-address");
   opt_policy_flags = has_option (line, "--policy-flags");
@@ -864,7 +868,8 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
   *domain++ = 0;
   domain_orig = domain;
 
-  /* First check whether we already know that the domain does not
+
+  /* Let's check whether we already know that the domain does not
    * support WKD.  */
   if (is_wkd_query)
     {
@@ -875,8 +880,41 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
         }
     }
 
-  /* Check for SRV records.  */
-  if (1)
+
+  /* First try the new "openpgp" subdomain.  We check that the domain
+   * is valid because it is later used as an unescaped filename part
+   * of the URI.  */
+  if (is_valid_domain_name (domain_orig))
+    {
+      dns_addrinfo_t aibuf;
+
+      domainbuf = strconcat ( "openpgpkey.", domain_orig, NULL);
+      if (!domainbuf)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+
+      /* FIXME: We should put a cache into dns-stuff because the same
+       * query (with a different port and socket type, though) will be
+       * done later by http function.  */
+      err = resolve_dns_name (ctrl, domainbuf, 0, 0, 0, &aibuf, NULL);
+      if (err)
+        {
+          err = 0;
+          xfree (domainbuf);
+          domainbuf = NULL;
+        }
+      else /* Got a subdomain. */
+        {
+          free_dns_addrinfo (aibuf);
+          subdomain_mode = 1;
+          domain = domainbuf;
+        }
+    }
+
+  /* Check for SRV records unless we have a subdomain. */
+  if (!subdomain_mode)
     {
       struct srventry *srvs;
       unsigned int srvscount;
@@ -931,6 +969,7 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
       xfree (srvs);
     }
 
+  /* Prepare the hash of the local part.  */
   gcry_md_hash_buffer (GCRY_MD_SHA1, sha1buf, mbox, strlen (mbox));
   encodedhash = zb32_encode (sha1buf, 8*20);
   if (!encodedhash)
@@ -944,7 +983,10 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
       uri = strconcat ("https://",
                        domain,
                        portstr,
-                       "/.well-known/openpgpkey/submission-address",
+                       "/.well-known/openpgpkey/",
+                       subdomain_mode? domain_orig : "",
+                       subdomain_mode? "/" : "",
+                       "submission-address",
                        NULL);
     }
   else if (opt_policy_flags)
@@ -952,7 +994,10 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
       uri = strconcat ("https://",
                        domain,
                        portstr,
-                       "/.well-known/openpgpkey/policy",
+                       "/.well-known/openpgpkey/",
+                       subdomain_mode? domain_orig : "",
+                       subdomain_mode? "/" : "",
+                       "policy",
                        NULL);
     }
   else
@@ -965,7 +1010,10 @@ proc_wkd_get (ctrl_t ctrl, assuan_context_t ctx, char *line)
           uri = strconcat ("https://",
                            domain,
                            portstr,
-                           "/.well-known/openpgpkey/hu/",
+                           "/.well-known/openpgpkey/",
+                           subdomain_mode? domain_orig : "",
+                           subdomain_mode? "/" : "",
+                           "hu/",
                            encodedhash,
                            "?l=",
                            escapedmbox,