diff --git a/common/Makefile.am b/common/Makefile.am index 4493ae7c5..d137df871 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -87,8 +87,6 @@ common_sources = \ signal.c \ audit.c audit.h \ srv.h \ - dns-cert.c dns-cert.h \ - pka.c pka.h \ localename.c \ session-env.c session-env.h \ userids.c userids.h \ @@ -177,8 +175,8 @@ if HAVE_W32_SYSTEM jnlib_tests += t-w32-reg endif module_tests = t-convert t-percent t-gettime t-sysutils t-sexputil \ - t-session-env t-openpgp-oid t-ssh-utils t-dns-cert \ - t-pka t-mapstrings t-zb32 t-mbox-util + t-session-env t-openpgp-oid t-ssh-utils \ + t-mapstrings t-zb32 t-mbox-util if !HAVE_W32CE_SYSTEM module_tests += t-exechelp endif @@ -221,8 +219,6 @@ t_exechelp_LDADD = $(t_common_ldadd) t_session_env_LDADD = $(t_common_ldadd) t_openpgp_oid_LDADD = $(t_common_ldadd) t_ssh_utils_LDADD = $(t_common_ldadd) -t_dns_cert_LDADD = $(t_common_ldadd) $(DNSLIBS) -t_pka_LDADD = $(t_common_ldadd) $(DNSLIBS) t_mapstrings_LDADD = $(t_common_ldadd) t_zb32_LDADD = $(t_common_ldadd) t_mbox_util_LDADD = $(t_common_ldadd) diff --git a/common/pka.c b/common/pka.c deleted file mode 100644 index 1aa5b3343..000000000 --- a/common/pka.c +++ /dev/null @@ -1,107 +0,0 @@ -/* pka.c - DNS Public Key Association RR access - * Copyright (C) 2005, 2009 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of either - * - * - the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at - * your option) any later version. - * - * or - * - * - the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * or both in parallel, as here. - * - * This file is 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 . - */ - -#include - -#include -#include -#include - -#include "util.h" -#include "mbox-util.h" -#include "dns-cert.h" -#include "pka.h" - - -/* For the given email ADDRESS lookup the PKA information in the DNS. - - On success the fingerprint is stored at FPRBUF and the URI will be - returned in an allocated buffer. Note that the URI might be a zero - length string as this information is optional. Caller must xfree - the returned string. FPRBUFLEN gives the size of the expected - fingerprint (usually 20). - - On error NULL is returned and the FPRBUF is not defined. */ -char * -get_pka_info (const char *address, void *fprbuf, size_t fprbuflen) -{ - char *result = NULL; - char *mbox; - char *domain; /* Points to mbox. */ - char hashbuf[20]; - char *hash = NULL; - char *name = NULL; - unsigned char *fpr = NULL; - size_t fpr_len; - char *url = NULL; - - mbox = mailbox_from_userid (address); - if (!mbox) - goto leave; - domain = strchr (mbox, '@'); - if (!domain) - goto leave; - *domain++ = 0; - - gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, mbox, strlen (mbox)); - hash = zb32_encode (hashbuf, 8*20); - if (!hash) - goto leave; - name = strconcat (hash, "._pka.", domain, NULL); - if (!name) - goto leave; - - if (get_dns_cert (name, DNS_CERTTYPE_IPGP, NULL, &fpr, &fpr_len, &url)) - goto leave; - if (!fpr) - goto leave; - - /* Return the fingerprint. */ - if (fpr_len != fprbuflen) - { - /* fprintf (stderr, "get_dns_cert failed: fprlen (%zu/%zu)\n", */ - /* fpr_len, fprbuflen); */ - goto leave; - } - memcpy (fprbuf, fpr, fpr_len); - - /* We return the URL or an empty string. */ - if (!url) - url = xtrycalloc (1, 1); - result = url; - url = NULL; - - leave: - xfree (fpr); - xfree (url); - xfree (name); - xfree (hash); - xfree (mbox); - return result; -} diff --git a/common/pka.h b/common/pka.h deleted file mode 100644 index 93a4eb3ee..000000000 --- a/common/pka.h +++ /dev/null @@ -1,35 +0,0 @@ -/* pka.h - DNS Public Key Association RR access definitions - * Copyright (C) 2006 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of either - * - * - the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at - * your option) any later version. - * - * or - * - * - the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * or both in parallel, as here. - * - * This file is 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 . - */ -#ifndef GNUPG_COMMON_PKA_H -#define GNUPG_COMMON_PKA_H - -char *get_pka_info (const char *address, void *fprbuf, size_t fprbuflen); - - -#endif /*GNUPG_COMMON_PKA_H*/ diff --git a/common/t-pka.c b/common/t-pka.c deleted file mode 100644 index 7c4d7c306..000000000 --- a/common/t-pka.c +++ /dev/null @@ -1,72 +0,0 @@ -/* t-pak.c - Module test for pka.c - * Copyright (C) 2015 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 . - */ - -#include -#include -#include -#include - -#include "util.h" -#include "pka.h" - - -int -main (int argc, char **argv) -{ - unsigned char fpr[20]; - char *url; - char const *name; - int i; - - if (argc) - { - argc--; - argv++; - } - - if (!argc) - name = "wk@gnupg.org"; - else if (argc == 1) - name = *argv; - else - { - fputs ("usage: t-pka [userid]\n", stderr); - return 1; - } - - printf ("User id ...: %s\n", name); - - url = get_pka_info (name, fpr, sizeof fpr); - printf ("Fingerprint: "); - if (url) - { - for (i = 0; i < sizeof fpr; i++) - printf ("%02X", fpr[i]); - } - else - printf ("[not found]"); - - putchar ('\n'); - - printf ("URL .......: %s\n", (url && *url)? url : "[none]"); - - xfree (url); - - return 0; -} diff --git a/dirmngr/Makefile.am b/dirmngr/Makefile.am index 906fe37eb..cee777a6a 100644 --- a/dirmngr/Makefile.am +++ b/dirmngr/Makefile.am @@ -61,6 +61,7 @@ dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c \ certcache.c certcache.h \ cdb.h cdblib.c misc.c dirmngr-err.h \ ocsp.c ocsp.h validate.c validate.h \ + dns-cert.c dns-cert.h \ ks-action.c ks-action.h ks-engine.h \ ks-engine-hkp.c ks-engine-http.c ks-engine-finger.c ks-engine-kdns.c @@ -113,7 +114,7 @@ t_common_ldadd = $(libcommontls) $(libcommon) no-libgcrypt.o \ $(NTBTLS_LIBS) $(LIBGNUTLS_LIBS) \ $(DNSLIBS) $(LIBINTL) $(LIBICONV) -module_tests = +module_tests = t-dns-cert if USE_LDAP module_tests += t-ldap-parse-uri @@ -124,4 +125,7 @@ t_ldap_parse_uri_SOURCES = \ $(ldap_url) $(t_common_src) t_ldap_parse_uri_LDADD = $(ldaplibs) $(t_common_ldadd) +t_dns_cert_SOURCES = t-dns-cert.c dns-cert.c +t_dns_cert_LDADD = $(t_common_ldadd) + $(PROGRAMS) : $(libcommon) $(libcommonpth) $(libcommontls) $(libcommontlsnpth) diff --git a/common/dns-cert.c b/dirmngr/dns-cert.c similarity index 93% rename from common/dns-cert.c rename to dirmngr/dns-cert.c index 405ca293e..de523b5f2 100644 --- a/common/dns-cert.c +++ b/dirmngr/dns-cert.c @@ -62,7 +62,7 @@ /* Returns 0 on success or an error code. If a PGP CERT record was - found, a new estream with that key will be returned at R_KEY and + found, the malloced data is returned at (R_KEY, R_KEYLEN) and the other return parameters are set to NULL/0. If an IPGP CERT record was found the fingerprint is stored as an allocated block at R_FPR and its length at R_FPRLEN; an URL is is allocated as a @@ -70,10 +70,10 @@ returns the first CERT found with a supported type; it is expected that only one CERT record is used. If WANT_CERTTYPE is one of the supported certtypes only records wih this certtype are considered - and the first found is returned. R_KEY is optional. */ + and the first found is returned. (R_KEY,R_KEYLEN) are optional. */ gpg_error_t get_dns_cert (const char *name, int want_certtype, - estream_t *r_key, + void **r_key, size_t *r_keylen, unsigned char **r_fpr, size_t *r_fprlen, char **r_url) { #ifdef USE_DNS_CERT @@ -86,6 +86,8 @@ get_dns_cert (const char *name, int want_certtype, if (r_key) *r_key = NULL; + if (r_keylen) + *r_keylen = 0; *r_fpr = NULL; *r_fprlen = 0; *r_url = NULL; @@ -130,16 +132,20 @@ get_dns_cert (const char *name, int want_certtype, if (want_certtype && want_certtype != ctype) ; /* Not of the requested certtype. */ - else if (ctype == DNS_CERTTYPE_PGP && datalen >= 11 && r_key) + else if (ctype == DNS_CERTTYPE_PGP && datalen >= 11 && r_key && r_keylen) { /* CERT type is PGP. Gpg checks for a minimum length of 11, thus we do the same. */ - *r_key = es_fopenmem_init (0, "rwb", data, datalen); + *r_key = xtrymalloc (datalen); if (!*r_key) err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ()); else - err = 0; + { + memcpy (*r_key, data, datalen); + *r_keylen = datalen; + err = 0; + } goto leave; } else if (ctype == DNS_CERTTYPE_IPGP && datalen && datalen < 1023 @@ -200,6 +206,8 @@ get_dns_cert (const char *name, int want_certtype, if (r_key) *r_key = NULL; + if (r_keylen) + *r_keylen = 0; *r_fpr = NULL; *r_fprlen = 0; *r_url = NULL; @@ -294,15 +302,19 @@ get_dns_cert (const char *name, int want_certtype, /* 15 bytes takes us to here */ if (want_certtype && want_certtype != ctype) ; /* Not of the requested certtype. */ - else if (ctype == DNS_CERTTYPE_PGP && dlen && r_key) + else if (ctype == DNS_CERTTYPE_PGP && dlen && r_key && r_keylen) { /* PGP type */ - *r_key = es_fopenmem_init (0, "rwb", pt, dlen); + *r_key = xtrymalloc (dlen); if (!*r_key) err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ()); else - err = 0; + { + memcpy (*r_key, pt, dlen); + *r_keylen = dlen; + err = 0; + } goto leave; } else if (ctype == DNS_CERTTYPE_IPGP @@ -359,6 +371,8 @@ get_dns_cert (const char *name, int want_certtype, (void)name; if (r_key) *r_key = NULL; + if (r_keylen) + *r_keylen = NULL; *r_fpr = NULL; *r_fprlen = 0; *r_url = NULL; diff --git a/common/dns-cert.h b/dirmngr/dns-cert.h similarity index 92% rename from common/dns-cert.h rename to dirmngr/dns-cert.h index 4b49efc1c..5a579ec1f 100644 --- a/common/dns-cert.h +++ b/dirmngr/dns-cert.h @@ -26,8 +26,8 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ -#ifndef GNUPG_COMMON_DNS_CERT_H -#define GNUPG_COMMON_DNS_CERT_H +#ifndef GNUPG_DIRMNGR_DNS_CERT_H +#define GNUPG_DIRMNGR_DNS_CERT_H #define DNS_CERTTYPE_ANY 0 /* Internal catch all type. */ @@ -46,10 +46,10 @@ gpg_error_t get_dns_cert (const char *name, int want_certtype, - estream_t *r_key, + void **r_key, size_t *r_keylen, unsigned char **r_fpr, size_t *r_fprlen, char **r_url); -#endif /*GNUPG_COMMON_DNS_CERT_H*/ +#endif /*GNUPG_DIRMNGR_DNS_CERT_H*/ diff --git a/dirmngr/server.c b/dirmngr/server.c index c0f63ac7d..df6c66fcc 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -51,6 +51,8 @@ #if USE_LDAP # include "ldap-parse-uri.h" #endif +#include "dns-cert.h" +#include "mbox-util.h" /* To avoid DoS attacks we limit the size of a certificate to something reasonable. */ @@ -150,13 +152,14 @@ leave_cmd (assuan_context_t ctx, gpg_error_t err) return err; } -/* A write handler used by es_fopencookie to write assuan data - lines. */ -static ssize_t -data_line_cookie_write (void *cookie, const void *buffer_arg, size_t size) + +/* This is a wrapper around assuan_send_data which makes debugging the + output in verbose mode easier. */ +static gpg_error_t +data_line_write (assuan_context_t ctx, const void *buffer_arg, size_t size) { - assuan_context_t ctx = cookie; const char *buffer = buffer_arg; + gpg_error_t err; if (opt.verbose && buffer && size) { @@ -169,33 +172,49 @@ data_line_cookie_write (void *cookie, const void *buffer_arg, size_t size) { p = memchr (buffer, '\n', nbytes); n = p ? (p - buffer) + 1 : nbytes; - if (assuan_send_data (ctx, buffer, n)) + err = assuan_send_data (ctx, buffer, n); + if (err) { gpg_err_set_errno (EIO); - return -1; + return err; } buffer += n; nbytes -= n; - if (nbytes && assuan_send_data (ctx, NULL, 0)) /* Flush line. */ + if (nbytes && (err=assuan_send_data (ctx, NULL, 0))) /* Flush line. */ { gpg_err_set_errno (EIO); - return -1; + return err; } } while (nbytes); } else { - if (assuan_send_data (ctx, buffer, size)) + err = assuan_send_data (ctx, buffer, size); + if (err) { - gpg_err_set_errno (EIO); - return -1; + gpg_err_set_errno (EIO); /* For use by data_line_cookie_write. */ + return err; } } - return size; + return 0; } + +/* A write handler used by es_fopencookie to write assuan data + lines. */ +static ssize_t +data_line_cookie_write (void *cookie, const void *buffer, size_t size) +{ + assuan_context_t ctx = cookie; + + if (data_line_write (ctx, buffer, size)) + return -1; + return (ssize_t)size; +} + + static int data_line_cookie_close (void *cookie) { @@ -609,6 +628,149 @@ option_handler (assuan_context_t ctx, const char *key, const char *value) } + +static const char hlp_dns_cert[] = + "DNS_CERT \n" + "DNS_CERT --pka \n" + "\n" + "Return the CERT record for . is one of\n" + " * Return the first record of any supported subtype\n" + " PGP Return the first record of subtype PGP (3)\n" + " IPGP Return the first record of subtype IPGP (6)\n" + "If the content of a certifciate is available (PGP) it is returned\n" + "by data lines. Fingerprints and URLs are returned via status lines.\n" + "In --pka mode the fingerprint and if available an URL is returned."; +static gpg_error_t +cmd_dns_cert (assuan_context_t ctx, char *line) +{ + /* ctrl_t ctrl = assuan_get_pointer (ctx); */ + gpg_error_t err = 0; + int pka_mode; + char *mbox = NULL; + char *namebuf = NULL; + char *encodedhash = NULL; + const char *name; + int certtype; + char *p; + void *key = NULL; + size_t keylen; + unsigned char *fpr = NULL; + size_t fprlen; + char *url = NULL; + + pka_mode = has_option (line, "--pka"); + line = skip_options (line); + if (pka_mode) + ; /* No need to parse here - we do this later. */ + else + { + p = strchr (line, ' '); + if (!p) + { + err = PARM_ERROR ("missing arguments"); + goto leave; + } + *p++ = 0; + if (!strcmp (line, "*")) + certtype = DNS_CERTTYPE_ANY; + else if (!strcmp (line, "IPGP")) + certtype = DNS_CERTTYPE_IPGP; + else if (!strcmp (line, "PGP")) + certtype = DNS_CERTTYPE_PGP; + else + { + err = PARM_ERROR ("unknown subtype"); + goto leave; + } + while (spacep (p)) + p++; + line = p; + if (!*line) + { + err = PARM_ERROR ("name missing"); + goto leave; + } + } + + if (pka_mode) + { + char *domain; /* Points to mbox. */ + char hashbuf[20]; + + mbox = mailbox_from_userid (line); + if (!mbox || !(domain = strchr (mbox, '@'))) + { + err = set_error (GPG_ERR_INV_USER_ID, "no mailbox in user id"); + goto leave; + } + *domain++ = 0; + + gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, mbox, strlen (mbox)); + encodedhash = zb32_encode (hashbuf, 8*20); + if (!encodedhash) + { + err = gpg_error_from_syserror (); + goto leave; + } + namebuf = strconcat (encodedhash, "._pka.", domain, NULL); + if (!namebuf) + { + err = gpg_error_from_syserror (); + goto leave; + } + name = namebuf; + certtype = DNS_CERTTYPE_IPGP; + } + else + name = line; + + err = get_dns_cert (name, certtype, &key, &keylen, &fpr, &fprlen, &url); + if (err) + goto leave; + + if (key) + { + err = data_line_write (ctx, key, keylen); + if (err) + goto leave; + } + + if (fpr) + { + char *tmpstr; + + tmpstr = bin2hex (fpr, fprlen, NULL); + if (!tmpstr) + err = gpg_error_from_syserror (); + else + { + err = assuan_write_status (ctx, "FPR", tmpstr); + xfree (tmpstr); + } + if (err) + goto leave; + } + + if (url) + { + err = assuan_write_status (ctx, "URL", url); + if (err) + goto leave; + } + + + leave: + xfree (key); + xfree (fpr); + xfree (url); + xfree (mbox); + xfree (namebuf); + xfree (encodedhash); + return leave_cmd (ctx, err); +} + + + static const char hlp_ldapserver[] = "LDAPSERVER \n" "\n" @@ -1919,6 +2081,7 @@ register_commands (assuan_context_t ctx) assuan_handler_t handler; const char * const help; } table[] = { + { "DNS_CERT", cmd_dns_cert, hlp_dns_cert }, { "LDAPSERVER", cmd_ldapserver, hlp_ldapserver }, { "ISVALID", cmd_isvalid, hlp_isvalid }, { "CHECKCRL", cmd_checkcrl, hlp_checkcrl }, diff --git a/common/t-dns-cert.c b/dirmngr/t-dns-cert.c similarity index 88% rename from common/t-dns-cert.c rename to dirmngr/t-dns-cert.c index a170ffb2d..61536c566 100644 --- a/common/t-dns-cert.c +++ b/dirmngr/t-dns-cert.c @@ -33,7 +33,8 @@ main (int argc, char **argv) unsigned char *fpr; size_t fpr_len; char *url; - estream_t key; + void *key; + size_t keylen; char const *name; if (argc) @@ -54,17 +55,14 @@ main (int argc, char **argv) printf ("CERT lookup on '%s'\n", name); - err = get_dns_cert (name, DNS_CERTTYPE_ANY, &key, &fpr, &fpr_len, &url); + err = get_dns_cert (name, DNS_CERTTYPE_ANY, &key, &keylen, + &fpr, &fpr_len, &url); if (err) printf ("get_dns_cert failed: %s <%s>\n", gpg_strerror (err), gpg_strsource (err)); else if (key) { - int count = 0; - - while (es_getc (key) != EOF) - count++; - printf ("Key found (%d bytes)\n", count); + printf ("Key found (%u bytes)\n", (unsigned int)keylen); } else { @@ -87,7 +85,7 @@ main (int argc, char **argv) } - es_fclose (key); + xfree (key); xfree (fpr); xfree (url); diff --git a/g10/Makefile.am b/g10/Makefile.am index b66abb84c..ca99314b7 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -141,8 +141,7 @@ gpgv2_SOURCES = gpgv.c \ # here, even that it is not used by gpg. A proper solution would # either to split up libkeybox.a or to use a separate keybox daemon. LDADD = $(needed_libs) ../common/libgpgrl.a \ - $(ZLIBS) $(DNSLIBS) \ - $(LIBINTL) $(CAPLIBS) $(NETLIBS) + $(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS) gpg2_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \ $(KSBA_LIBS) $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \ $(LIBICONV) $(resource_objs) $(extra_sys_libs) diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c index bb571b2e9..e452c971e 100644 --- a/g10/call-dirmngr.c +++ b/g10/call-dirmngr.c @@ -78,6 +78,16 @@ struct ks_put_parm_s }; +/* Parameter structure used with the DNS_CERT command. */ +struct dns_cert_parm_s +{ + estream_t memfp; + unsigned char *fpr; + size_t fprlen; + char *url; +}; + + /* Data used to associate an session with dirmngr contexts. We can't use a simple one to one mapping because we sometimes need two connections to the dirmngr; for example while doing a listing and @@ -957,3 +967,228 @@ gpg_dirmngr_ks_put (ctrl_t ctrl, void *data, size_t datalen, kbnode_t keyblock) close_context (ctrl, ctx); return err; } + + + +/* Data callback for the DNS_CERT command. */ +static gpg_error_t +dns_cert_data_cb (void *opaque, const void *data, size_t datalen) +{ + struct dns_cert_parm_s *parm = opaque; + gpg_error_t err = 0; + size_t nwritten; + + if (!data) + return 0; /* Ignore END commands. */ + if (!parm->memfp) + return 0; /* Data is not required. */ + + if (es_write (parm->memfp, data, datalen, &nwritten)) + err = gpg_error_from_syserror (); + + return err; +} + + +/* Status callback for the DNS_CERT command. */ +static gpg_error_t +dns_cert_status_cb (void *opaque, const char *line) +{ + struct dns_cert_parm_s *parm = opaque; + gpg_error_t err = 0; + const char *s; + size_t nbytes; + + if ((s = has_leading_keyword (line, "FPR"))) + { + char *buf; + + if (!(buf = xtrystrdup (s))) + err = gpg_error_from_syserror (); + else if (parm->fpr) + err = gpg_error (GPG_ERR_DUP_KEY); + else if (!hex2str (buf, buf, strlen (buf)+1, &nbytes)) + err = gpg_error_from_syserror (); + else if (nbytes < 20) + err = gpg_error (GPG_ERR_TOO_SHORT); + else + { + parm->fpr = xtrymalloc (nbytes); + if (!parm->fpr) + err = gpg_error_from_syserror (); + else + memcpy (parm->fpr, buf, (parm->fprlen = nbytes)); + } + xfree (buf); + } + else if ((s = has_leading_keyword (line, "URL")) && *s) + { + if (parm->url) + err = gpg_error (GPG_ERR_DUP_KEY); + else if (!(parm->fpr = xtrymalloc (nbytes))) + err = gpg_error_from_syserror (); + else + memcpy (parm->fpr, line, (parm->fprlen = nbytes)); + } + + return err; +} + +/* Ask the dirmngr for a DNS CERT record. Depending on the found + subtypes different return values are set: + + - For a PGP subtype a new estream with that key will be returned at + R_KEY and the other return parameters are set to NULL/0. + + - For an IPGP subtype the fingerprint is stored as a malloced block + at (R_FPR,R_FPRLEN). If an URL is available it is stored as a + malloced string at R_URL; NULL is stored if there is no URL. + + If CERTTYPE is DNS_CERTTYPE_ANY this function returns the first + CERT record found with a supported type; it is expected that only + one CERT record is used. If CERTTYPE is one of the supported + certtypes, only records with this certtype are considered and the + first one found is returned. All R_* args are optional. */ +gpg_error_t +gpg_dirmngr_dns_cert (ctrl_t ctrl, const char *name, const char *certtype, + estream_t *r_key, + unsigned char **r_fpr, size_t *r_fprlen, + char **r_url) +{ + gpg_error_t err; + assuan_context_t ctx; + struct dns_cert_parm_s parm; + char *line = NULL; + + memset (&parm, 0, sizeof parm); + if (r_key) + *r_key = NULL; + if (r_fpr) + *r_fpr = NULL; + if (r_fprlen) + *r_fprlen = 0; + if (r_url) + *r_url = NULL; + + err = open_context (ctrl, &ctx); + if (err) + return err; + + line = es_bsprintf ("DNS_CERT %s %s", certtype, name); + if (!line) + { + err = gpg_error_from_syserror (); + goto leave; + } + if (strlen (line) + 2 >= ASSUAN_LINELENGTH) + { + err = gpg_error (GPG_ERR_TOO_LARGE); + goto leave; + } + + parm.memfp = es_fopenmem (0, "rwb"); + if (!parm.memfp) + { + err = gpg_error_from_syserror (); + goto leave; + } + err = assuan_transact (ctx, line, dns_cert_data_cb, &parm, + NULL, NULL, dns_cert_status_cb, &parm); + if (err) + goto leave; + + if (r_key) + { + es_rewind (parm.memfp); + *r_key = parm.memfp; + parm.memfp = NULL; + } + + if (r_fpr && parm.fpr) + { + *r_fpr = parm.fpr; + parm.fpr = NULL; + } + if (r_fprlen) + *r_fprlen = parm.fprlen; + + if (r_url && parm.url) + { + *r_url = parm.url; + parm.url = NULL; + } + + leave: + xfree (parm.fpr); + xfree (parm.url); + es_fclose (parm.memfp); + xfree (line); + close_context (ctrl, ctx); + return err; +} + + +/* Ask the dirmngr for PKA info. On success the retrieved fingerprint + is returned in a malloced buffer at R_FPR and its length is stored + at R_FPRLEN. If an URL is available it is stored as a malloced + string at R_URL. On error all return values are set to NULL/0. */ +gpg_error_t +gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid, + unsigned char **r_fpr, size_t *r_fprlen, + char **r_url) +{ + gpg_error_t err; + assuan_context_t ctx; + struct dns_cert_parm_s parm; + char *line = NULL; + + memset (&parm, 0, sizeof parm); + if (r_fpr) + *r_fpr = NULL; + if (r_fprlen) + *r_fprlen = 0; + if (r_url) + *r_url = NULL; + + err = open_context (ctrl, &ctx); + if (err) + return err; + + line = es_bsprintf ("DNS_CERT --pka -- %s", userid); + if (!line) + { + err = gpg_error_from_syserror (); + goto leave; + } + if (strlen (line) + 2 >= ASSUAN_LINELENGTH) + { + err = gpg_error (GPG_ERR_TOO_LARGE); + goto leave; + } + + err = assuan_transact (ctx, line, dns_cert_data_cb, &parm, + NULL, NULL, dns_cert_status_cb, &parm); + if (err) + goto leave; + + if (r_fpr && parm.fpr) + { + *r_fpr = parm.fpr; + parm.fpr = NULL; + } + if (r_fprlen) + *r_fprlen = parm.fprlen; + + if (r_url && parm.url) + { + *r_url = parm.url; + parm.url = NULL; + } + + leave: + xfree (parm.fpr); + xfree (parm.url); + xfree (line); + close_context (ctrl, ctx); + return err; +} diff --git a/g10/call-dirmngr.h b/g10/call-dirmngr.h index bae11238c..b9b8e21a3 100644 --- a/g10/call-dirmngr.h +++ b/g10/call-dirmngr.h @@ -31,6 +31,14 @@ gpg_error_t gpg_dirmngr_ks_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp); gpg_error_t gpg_dirmngr_ks_put (ctrl_t ctrl, void *data, size_t datalen, kbnode_t keyblock); +gpg_error_t gpg_dirmngr_dns_cert (ctrl_t ctrl, + const char *name, const char *certtype, + estream_t *r_key, + unsigned char **r_fpr, size_t *r_fprlen, + char **r_url); +gpg_error_t gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid, + unsigned char **r_fpr, size_t *r_fprlen, + char **r_url); #endif /*GNUPG_G10_CALL_DIRMNGR_H*/ diff --git a/g10/gpgv.c b/g10/gpgv.c index 157fdea45..479bb9599 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -575,3 +575,19 @@ agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno) *r_serialno = NULL; return gpg_error (GPG_ERR_NO_SECKEY); } + +gpg_error_t +gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid, + unsigned char **r_fpr, size_t *r_fprlen, + char **r_url) +{ + (void)ctrl; + (void)userid; + if (r_fpr) + *r_fpr = NULL; + if (r_fprlen) + *r_fprlen = 0; + if (r_url) + *r_url = NULL; + return gpg_error (GPG_ERR_NOT_FOUND); +} diff --git a/g10/keyserver-internal.h b/g10/keyserver-internal.h index a955fc7da..fc1c3435d 100644 --- a/g10/keyserver-internal.h +++ b/g10/keyserver-internal.h @@ -42,8 +42,8 @@ gpg_error_t keyserver_search (ctrl_t ctrl, strlist_t tokens); int keyserver_fetch (ctrl_t ctrl, strlist_t urilist); int keyserver_import_cert (ctrl_t ctrl, const char *name, unsigned char **fpr,size_t *fpr_len); -int keyserver_import_pka (ctrl_t ctrl, - const char *name,unsigned char **fpr,size_t *fpr_len); +gpg_error_t keyserver_import_pka (ctrl_t ctrl, const char *name, + unsigned char **fpr,size_t *fpr_len); int keyserver_import_name (ctrl_t ctrl, const char *name,unsigned char **fpr,size_t *fpr_len, struct keyserver_spec *keyserver); diff --git a/g10/keyserver.c b/g10/keyserver.c index abe4bdebf..40ba49a61 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -41,8 +41,6 @@ #include "trustdb.h" #include "keyserver-internal.h" #include "util.h" -#include "dns-cert.h" -#include "pka.h" #ifdef USE_DNS_SRV #include "srv.h" #endif @@ -1897,7 +1895,7 @@ keyserver_import_cert (ctrl_t ctrl, if(domain) *domain='.'; - err = get_dns_cert (look, DNS_CERTTYPE_ANY, &key, fpr, fpr_len, &url); + err = gpg_dirmngr_dns_cert (ctrl, look, "*", &key, fpr, fpr_len, &url); if (err) ; else if (key) @@ -1957,37 +1955,35 @@ keyserver_import_cert (ctrl_t ctrl, /* Import key pointed to by a PKA record. Return the requested fingerprint in fpr. */ -int -keyserver_import_pka (ctrl_t ctrl, - const char *name,unsigned char **fpr,size_t *fpr_len) +gpg_error_t +keyserver_import_pka (ctrl_t ctrl, const char *name, + unsigned char **fpr, size_t *fpr_len) { - char *uri; - int rc = GPG_ERR_NO_PUBKEY; + gpg_error_t err; + char *url; - *fpr = xmalloc (20); - *fpr_len = 20; - - uri = get_pka_info (name, *fpr, 20); - if (uri && *uri) + err = gpg_dirmngr_get_pka (ctrl, name, fpr, fpr_len, &url); + if (url && *url && fpr && fpr_len) { - /* An URI is available. Lookup the key. */ + /* An URL is available. Lookup the key. */ struct keyserver_spec *spec; - spec = parse_keyserver_uri (uri, 1); + spec = parse_keyserver_uri (url, 1); if (spec) { - rc = keyserver_import_fprint (ctrl, *fpr, 20, spec); + err = keyserver_import_fprint (ctrl, *fpr, *fpr_len, spec); free_keyserver_spec (spec); } } - xfree (uri); + xfree (url); - if (rc) + if (err) { xfree(*fpr); *fpr = NULL; + *fpr_len = 0; } - return rc; + return err; } diff --git a/g10/mainproc.c b/g10/mainproc.c index 0f6ba2b32..e72d07640 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -38,9 +38,8 @@ #include "trustdb.h" #include "keyserver-internal.h" #include "photoid.h" -#include "pka.h" #include "mbox-util.h" - +#include "call-dirmngr.h" /* Put an upper limit on nested packets. The 32 is an arbitrary value, a much lower should actually be sufficient. */ @@ -1487,7 +1486,7 @@ get_pka_address (PKT_signature *sig) be retrieved for the signature we merely return it; if not we go out and try to get that DNS record. */ static const char * -pka_uri_from_sig (PKT_signature *sig) +pka_uri_from_sig (CTX c, PKT_signature *sig) { if (!sig->flags.pka_tried) { @@ -1496,17 +1495,28 @@ pka_uri_from_sig (PKT_signature *sig) sig->pka_info = get_pka_address (sig); if (sig->pka_info) { - char *uri; + char *url; + unsigned char *fpr; + size_t fprlen; - uri = get_pka_info (sig->pka_info->email, - sig->pka_info->fpr, sizeof sig->pka_info->fpr); - if (uri) + if (!gpg_dirmngr_get_pka (c->ctrl, sig->pka_info->email, + &fpr, &fprlen, &url)) { - sig->pka_info->valid = 1; - if (!*uri) - xfree (uri); - else - sig->pka_info->uri = uri; + if (fpr && fprlen == sizeof sig->pka_info->fpr) + { + memcpy (sig->pka_info->fpr, fpr, fprlen); + if (url) + { + sig->pka_info->valid = 1; + if (!*url) + xfree (url); + else + sig->pka_info->uri = url; + url = NULL; + } + } + xfree (fpr); + xfree (url); } } } @@ -1734,7 +1744,7 @@ check_sig_and_print (CTX c, kbnode_t node) && (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE) && (opt.keyserver_options.options & KEYSERVER_HONOR_PKA_RECORD)) { - const char *uri = pka_uri_from_sig (sig); + const char *uri = pka_uri_from_sig (c, sig); if (uri) { @@ -1997,7 +2007,7 @@ check_sig_and_print (CTX c, kbnode_t node) if (!rc) { if ((opt.verify_options & VERIFY_PKA_LOOKUPS)) - pka_uri_from_sig (sig); /* Make sure PKA info is available. */ + pka_uri_from_sig (c, sig); /* Make sure PKA info is available. */ rc = check_signatures_trust (sig); }