]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
systemd-resolve: allow easy querying of openpgp keys
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 28 Jan 2016 23:24:27 +0000 (18:24 -0500)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 11 Feb 2016 18:12:41 +0000 (13:12 -0500)
$ systemd-resolve --openpgp zbyszek@fedoraproject.org
d08ee310438ca124a6149ea5cc21b6313b390dce485576eff96f8722._openpgpkey.fedoraproject.org. IN OPENPGPKEY
        mQINBFBHPMsBEACeInGYJCb+7TurKfb6wGyTottCDtiSJB310i37/6ZYoeIay/5soJjlM
        yfMFQ9T2XNT/0LM6gTa0MpC1st9LnzYTMsT6tzRly1D1UbVI6xw0g0vE5y2Cjk3xUwAyn
        ...

Makefile.am
man/systemd-resolve.xml
src/resolve/resolve-tool.c
src/shared/gcrypt-util.c
src/shared/gcrypt-util.h

index d2cf9360ed23752ac53c4005f7b0097853d7dc8b..e63015476cd88727eb47a472b1ed0711dab1d5f0 100644 (file)
@@ -5291,7 +5291,9 @@ systemd_resolve_SOURCES = \
        src/resolve/resolved-dns-question.c \
        src/resolve/resolved-dns-question.h \
        src/resolve/dns-type.c \
-       src/resolve/dns-type.h
+       src/resolve/dns-type.h \
+       src/shared/gcrypt-util.c \
+       src/shared/gcrypt-util.h
 
 nodist_systemd_resolve_SOURCES = \
        src/resolve/dns_type-from-name.h \
index f1e663c5bb9f6fbca665bb2607f9e81e44e2cd88..0defa2d7fbbb1b62dc90ebbab3e1a5cd39aadb22 100644 (file)
       <replaceable>TYPE</replaceable></arg> <replaceable>DOMAIN</replaceable></arg>
     </cmdsynopsis>
 
+    <cmdsynopsis>
+      <command>systemd-resolve</command>
+      <arg choice="opt" rep="repeat">OPTIONS</arg>
+      <command> --openpgp</command>
+      <arg choice="plain"><replaceable>USER@DOMAIN</replaceable></arg>
+    </cmdsynopsis>
+
     <cmdsynopsis>
       <command>systemd-resolve</command>
       <arg choice="opt" rep="repeat">OPTIONS</arg>
     is assumed to be a domain name, that is already prefixed with an SRV type, and an SRV lookup is done (no
     TXT).</para>
 
+    <para>The <option>--openpgp</option> switch may be use to query PGP keys stored as the
+    <ulink url="https://tools.ietf.org/html/draft-wouters-dane-openpgp-02">OPENPGPKEY</ulink> resource records.
+    When this option is specified one or more e-mail address must be specified.</para>
+
     <para>The <option>--statistics</option> switch may be used to show resolver statistics, including information about
     the number of succesful and failed DNSSEC validations.</para>
 
         <option>--service</option> the TXT service metadata record is resolved as well.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--openpgp</option></term>
+
+        <listitem><para>Enables OPENPGPKEY resource record resolution (see above). Specified e-mail
+        addresses are converted to the corresponding DNS domain name, and any OPENPGPKEY keys are
+        printed.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>--cname=</option><replaceable>BOOL</replaceable></term>
 
index 9bee9538391c2d900df61cd71f7a396b607334d5..6d1bc6d0f9c84a0f3fe69d9ee9878227325c78b4 100644 (file)
@@ -19,6 +19,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <gcrypt.h>
 #include <getopt.h>
 #include <net/if.h>
 
@@ -30,6 +31,7 @@
 #include "bus-util.h"
 #include "escape.h"
 #include "in-addr-util.h"
+#include "gcrypt-util.h"
 #include "parse-util.h"
 #include "resolved-def.h"
 #include "resolved-dns-packet.h"
@@ -48,6 +50,7 @@ static enum {
         MODE_RESOLVE_HOST,
         MODE_RESOLVE_RECORD,
         MODE_RESOLVE_SERVICE,
+        MODE_RESOLVE_OPENPGP,
         MODE_STATISTICS,
         MODE_RESET_STATISTICS,
 } arg_mode = MODE_RESOLVE_HOST;
@@ -547,15 +550,10 @@ static int resolve_rfc4501(sd_bus *bus, const char *name) {
         } else
                 n = p;
 
-        if (type == 0)
-                type = arg_type;
-        if (type == 0)
-                type = DNS_TYPE_A;
-
         if (class == 0)
-                class = arg_class;
-        if (class == 0)
-                class = DNS_CLASS_IN;
+                class = arg_class ?: DNS_CLASS_IN;
+        if (type == 0)
+                type = arg_type ?: DNS_TYPE_A;
 
         return resolve_record(bus, n, class, type);
 
@@ -765,6 +763,36 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons
         return 0;
 }
 
+static int resolve_openpgp(sd_bus *bus, const char *address) {
+        const char *domain, *full;
+        int r;
+        _cleanup_free_ char *hashed = NULL;
+
+        assert(bus);
+        assert(address);
+
+        domain = strrchr(address, '@');
+        if (!domain) {
+                log_error("Address does not contain '@': \"%s\"", address);
+                return -EINVAL;
+        } else if (domain == address || domain[1] == '\0') {
+                log_error("Address starts or ends with '@': \"%s\"", address);
+                return -EINVAL;
+        }
+        domain++;
+
+        r = string_hashsum(address, domain - 1 - address, GCRY_MD_SHA224, &hashed);
+        if (r < 0)
+                return log_error_errno(r, "Hashing failed: %m");
+
+        full = strjoina(hashed, "._openpgpkey.", domain);
+        log_debug("Looking up \"%s\".", full);
+
+        return resolve_record(bus, full,
+                              arg_class ?: DNS_CLASS_IN,
+                              arg_type ?: DNS_TYPE_OPENPGPKEY);
+}
+
 static int show_statistics(sd_bus *bus) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
@@ -947,6 +975,7 @@ static void help(void) {
                "     --service                Resolve service (SRV)\n"
                "     --service-address=BOOL   Do [not] resolve address for services\n"
                "     --service-txt=BOOL       Do [not] resolve TXT records for services\n"
+               "     --openpgp                Query OpenPGP public key\n"
                "     --cname=BOOL             Do [not] follow CNAME redirects\n"
                "     --search=BOOL            Do [not] use search domains\n"
                "     --legend=BOOL            Do [not] print column headers and meta information\n"
@@ -963,6 +992,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_CNAME,
                 ARG_SERVICE_ADDRESS,
                 ARG_SERVICE_TXT,
+                ARG_OPENPGP,
                 ARG_SEARCH,
                 ARG_STATISTICS,
                 ARG_RESET_STATISTICS,
@@ -980,6 +1010,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "service",          no_argument,       NULL, ARG_SERVICE          },
                 { "service-address",  required_argument, NULL, ARG_SERVICE_ADDRESS  },
                 { "service-txt",      required_argument, NULL, ARG_SERVICE_TXT      },
+                { "openpgp",          no_argument,       NULL, ARG_OPENPGP          },
                 { "search",           required_argument, NULL, ARG_SEARCH           },
                 { "statistics",       no_argument,       NULL, ARG_STATISTICS,      },
                 { "reset-statistics", no_argument,       NULL, ARG_RESET_STATISTICS },
@@ -1089,6 +1120,10 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_mode = MODE_RESOLVE_SERVICE;
                         break;
 
+                case ARG_OPENPGP:
+                        arg_mode = MODE_RESOLVE_OPENPGP;
+                        break;
+
                 case ARG_CNAME:
                         r = parse_boolean(optarg);
                         if (r < 0)
@@ -1248,6 +1283,24 @@ int main(int argc, char **argv) {
 
                 break;
 
+        case MODE_RESOLVE_OPENPGP:
+                if (argc < optind + 1) {
+                        log_error("E-mail address required.");
+                        r = -EINVAL;
+                        goto finish;
+
+                }
+
+                r = 0;
+                while (optind < argc) {
+                        int k;
+
+                        k = resolve_openpgp(bus, argv[optind++]);
+                        if (k < 0)
+                                r = k;
+                }
+                break;
+
         case MODE_STATISTICS:
                 if (argc > optind) {
                         log_error("Too many arguments.");
index 3bbc161ef211bf6d697f9e01aa23bb59d9bfb6e4..b88724384930d7242fb00cebc4368c0efb62f613 100644 (file)
@@ -38,3 +38,32 @@ void initialize_libgcrypt(bool secmem) {
                 gcry_control(GCRYCTL_DISABLE_SECMEM);
         gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
 }
+
+int string_hashsum(const char *s, size_t len, int md_algorithm, char **out) {
+        gcry_md_hd_t md = NULL;
+        size_t hash_size;
+        void *hash;
+        char *enc;
+
+        initialize_libgcrypt(false);
+
+        hash_size = gcry_md_get_algo_dlen(md_algorithm);
+        assert(hash_size > 0);
+
+        gcry_md_open(&md, md_algorithm, 0);
+        if (!md)
+                return -EIO;
+
+        gcry_md_write(md, s, len);
+
+        hash = gcry_md_read(md, 0);
+        if (!hash)
+                return -EIO;
+
+        enc = hexmem(hash, hash_size);
+        if (!enc)
+                return -ENOMEM;
+
+        *out = enc;
+        return 0;
+}
index 42ce3fd1213a3bfb35efaca342b47bf7ffa0086d..c7652c22d18968154637d1b415340dc5d2e4a791 100644 (file)
@@ -22,3 +22,4 @@
 #include <stdbool.h>
 
 void initialize_libgcrypt(bool secmem);
+int string_hashsum(const char *s, size_t len, int md_algorithm, char **out);