diff options
-rw-r--r-- | common/Makefile.am | 3 | ||||
-rw-r--r-- | common/dns-cert.c | 15 | ||||
-rw-r--r-- | common/pka.c | 341 | ||||
-rw-r--r-- | common/pka.h | 2 | ||||
-rw-r--r-- | common/t-pka.c | 72 | ||||
-rw-r--r-- | configure.ac | 17 | ||||
-rw-r--r-- | g10/getkey.c | 2 | ||||
-rw-r--r-- | g10/keyserver.c | 2 | ||||
-rw-r--r-- | g10/mainproc.c | 3 |
9 files changed, 143 insertions, 314 deletions
diff --git a/common/Makefile.am b/common/Makefile.am index df2dafe46..2ba6dc007 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -178,7 +178,7 @@ 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-mapstrings t-zb32 t-mbox-util + t-pka t-mapstrings t-zb32 t-mbox-util if !HAVE_W32CE_SYSTEM module_tests += t-exechelp endif @@ -222,6 +222,7 @@ 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/dns-cert.c b/common/dns-cert.c index e7be2759b..405ca293e 100644 --- a/common/dns-cert.c +++ b/common/dns-cert.c @@ -70,7 +70,7 @@ 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. */ + and the first found is returned. R_KEY is optional. */ gpg_error_t get_dns_cert (const char *name, int want_certtype, estream_t *r_key, @@ -84,7 +84,8 @@ get_dns_cert (const char *name, int want_certtype, unsigned int ctype; int count; - *r_key = NULL; + if (r_key) + *r_key = NULL; *r_fpr = NULL; *r_fprlen = 0; *r_url = NULL; @@ -129,7 +130,7 @@ 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) + else if (ctype == DNS_CERTTYPE_PGP && datalen >= 11 && r_key) { /* CERT type is PGP. Gpg checks for a minimum length of 11, thus we do the same. */ @@ -197,7 +198,8 @@ get_dns_cert (const char *name, int want_certtype, int r; u16 count; - *r_key = NULL; + if (r_key) + *r_key = NULL; *r_fpr = NULL; *r_fprlen = 0; *r_url = NULL; @@ -292,7 +294,7 @@ 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) + else if (ctype == DNS_CERTTYPE_PGP && dlen && r_key) { /* PGP type */ *r_key = es_fopenmem_init (0, "rwb", pt, dlen); @@ -355,7 +357,8 @@ get_dns_cert (const char *name, int want_certtype, #endif /*!USE_ADNS */ #else /* !USE_DNS_CERT */ (void)name; - *r_key = NULL; + if (r_key) + *r_key = NULL; *r_fpr = NULL; *r_fprlen = 0; *r_url = NULL; diff --git a/common/pka.c b/common/pka.c index 4ead97f63..c3c68b538 100644 --- a/common/pka.c +++ b/common/pka.c @@ -33,307 +33,76 @@ #include <stdlib.h> #include <string.h> -#ifdef USE_DNS_PKA -#include <sys/types.h> -#ifdef _WIN32 -# ifdef HAVE_WINSOCK2_H -# include <winsock2.h> -# endif -# include <windows.h> -#else -#include <netinet/in.h> -#include <arpa/nameser.h> -#include <resolv.h> -#endif -#endif /* USE_DNS_PKA */ -#ifdef USE_ADNS -# include <adns.h> -#endif - #include "util.h" -#include "host2net.h" +#include "mbox-util.h" +#include "dns-cert.h" #include "pka.h" -#ifdef USE_DNS_PKA -/* Parse the TXT resource record. Format is: - - v=pka1;fpr=a4d94e92b0986ab5ee9dcd755de249965b0358a2;uri=string - - For simplicity white spaces are not allowed. Because we expect to - use a new RRTYPE for this in the future we define the TXT really - strict for simplicity: No white spaces, case sensitivity of the - names, order must be as given above. Only URI is optional. - - This function modifies BUFFER. On success 0 is returned, the 20 - byte fingerprint stored at FPR and BUFFER contains the URI or an - empty string. -*/ -static int -parse_txt_record (char *buffer, unsigned char *fpr) -{ - char *p, *pend; - int i; - - p = buffer; - pend = strchr (p, ';'); - if (!pend) - return -1; - *pend++ = 0; - if (strcmp (p, "v=pka1")) - return -1; /* Wrong or missing version. */ - - p = pend; - pend = strchr (p, ';'); - if (pend) - *pend++ = 0; - if (strncmp (p, "fpr=", 4)) - return -1; /* Missing fingerprint part. */ - p += 4; - for (i=0; i < 20 && hexdigitp (p) && hexdigitp (p+1); i++, p += 2) - fpr[i] = xtoi_2 (p); - if (i != 20) - return -1; /* Fingerprint consists not of exactly 40 hexbytes. */ - - p = pend; - if (!p || !*p) - { - *buffer = 0; - return 0; /* Success (no URI given). */ - } - if (strncmp (p, "uri=", 4)) - return -1; /* Unknown part. */ - p += 4; - /* There is an URI, copy it to the start of the buffer. */ - while (*p) - *buffer++ = *p++; - *buffer = 0; - return 0; -} - /* For the given email ADDRESS lookup the PKA information in the DNS. - On success the 20 byte SHA-1 fingerprint is stored at FPR and the - URI will be returned in an allocated buffer. Note that the URI - might be an zero length string as this information is optional. - Caller must xfree the returned string. + 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 20 bytes at FPR are not - defined. */ + On error NULL is returned and the FPRBUF is not defined. */ char * -get_pka_info (const char *address, unsigned char *fpr) +get_pka_info (const char *address, void *fprbuf, size_t fprbuflen) { -#ifdef USE_ADNS - int rc; - adns_state state; - const char *domain; - char *name; - adns_answer *answer = NULL; - char *buffer = NULL; - - domain = strrchr (address, '@'); - if (!domain || domain == address || !domain[1]) - return NULL; /* Invalid mail address given. */ - name = xtrymalloc (strlen (address) + 5 + 1); + 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; + gpg_error_t err; + + 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) - return NULL; - memcpy (name, address, domain - address); - strcpy (stpcpy (name + (domain-address), "._pka."), domain+1); - - rc = adns_init (&state, adns_if_noerrprint, NULL); - if (rc) - { - log_error ("error initializing adns: %s\n", strerror (errno)); - xfree (name); - return NULL; - } + goto leave; - rc = adns_synchronous (state, name, adns_r_txt, adns_qf_quoteok_query, - &answer); - xfree (name); - if (rc) - { - log_error ("DNS query failed: %s\n", strerror (errno)); - adns_finish (state); - return NULL; - } - if (answer->status != adns_s_ok - || answer->type != adns_r_txt || !answer->nrrs) - { - log_error ("DNS query returned an error: %s (%s)\n", - adns_strerror (answer->status), - adns_errabbrev (answer->status)); - adns_free (answer); - adns_finish (state); - return NULL; - } + if (get_dns_cert (name, DNS_CERTTYPE_IPGP, NULL, &fpr, &fpr_len, &url)) + goto leave; + if (!fpr) + goto leave; - /* We use a PKA records iff there is exactly one record. */ - if (answer->nrrs == 1 && answer->rrs.manyistr[0]->i != -1) + /* Return the fingerprint. */ + if (fpr_len != fprbuflen) { - buffer = xtrystrdup (answer->rrs.manyistr[0]->str); - if (parse_txt_record (buffer, fpr)) - { - xfree (buffer); - buffer = NULL; /* Not a valid gpg trustdns RR. */ - } + /* fprintf (stderr, "get_dns_cert failed: fprlen (%zu/%zu)\n", */ + /* fpr_len, fprbuflen); */ + goto leave; } + memcpy (fprbuf, fpr, fpr_len); - adns_free (answer); - adns_finish (state); - return buffer; - -#else /*!USE_ADNS*/ - unsigned char answer[PACKETSZ]; - int anslen; - int qdcount, ancount; - int rc; - unsigned char *p, *pend; - const char *domain; - char *name; - HEADER header; - - domain = strrchr (address, '@'); - if (!domain || domain == address || !domain[1]) - return NULL; /* invalid mail address given. */ + /* We return the URL or an empty string. */ + if (!url) + url = xtrycalloc (1, 1); + result = url; + url = NULL; - name = xtrymalloc (strlen (address) + 5 + 1); - if (!name) - return NULL; - memcpy (name, address, domain - address); - strcpy (stpcpy (name + (domain-address), "._pka."), domain+1); - - anslen = res_query (name, C_IN, T_TXT, answer, PACKETSZ); + leave: + xfree (fpr); + xfree (url); xfree (name); - if (anslen < sizeof(HEADER)) - return NULL; /* DNS resolver returned a too short answer. */ - - /* Don't despair: A good compiler should optimize this away, as - header is just 32 byte and constant at compile time. It's - one way to comply with strict aliasing rules. */ - memcpy (&header, answer, sizeof (header)); - - if ( (rc=header.rcode) != NOERROR ) - return NULL; /* DNS resolver returned an error. */ - - /* We assume that PACKETSZ is large enough and don't do dynmically - expansion of the buffer. */ - if (anslen > PACKETSZ) - return NULL; /* DNS resolver returned a too long answer */ - - qdcount = ntohs (header.qdcount); - ancount = ntohs (header.ancount); - - if (!ancount) - return NULL; /* Got no answer. */ - - p = answer + sizeof (HEADER); - pend = answer + anslen; /* Actually points directly behind the buffer. */ - - while (qdcount-- && p < pend) - { - rc = dn_skipname (p, pend); - if (rc == -1) - return NULL; - p += rc + QFIXEDSZ; - } - - if (ancount > 1) - return NULL; /* more than one possible gpg trustdns record - none used. */ - - while (ancount-- && p <= pend) - { - unsigned int type, class, txtlen, n; - char *buffer, *bufp; - - rc = dn_skipname (p, pend); - if (rc == -1) - return NULL; - p += rc; - if (p >= pend - 10) - return NULL; /* RR too short. */ - - type = buf16_to_uint (p); - p += 2; - class = buf16_to_uint (p); - p += 2; - p += 4; - txtlen = buf16_to_uint (p); - p += 2; - - if (type != T_TXT || class != C_IN) - return NULL; /* Answer does not match the query. */ - - buffer = bufp = xmalloc (txtlen + 1); - while (txtlen && p < pend) - { - for (n = *p++, txtlen--; txtlen && n && p < pend; txtlen--, n--) - *bufp++ = *p++; - } - *bufp = 0; - if (parse_txt_record (buffer, fpr)) - { - xfree (buffer); - return NULL; /* Not a valid gpg trustdns RR. */ - } - return buffer; - } - - return NULL; -#endif /*!USE_ADNS*/ + xfree (hash); + xfree (mbox); + return result; } - -#else /* !USE_DNS_PKA */ - -/* Dummy version of the function if we can't use the resolver - functions. */ -char * -get_pka_info (const char *address, unsigned char *fpr) -{ - (void)address; - (void)fpr; - return NULL; -} -#endif /* !USE_DNS_PKA */ - - -#ifdef TEST -int -main(int argc,char *argv[]) -{ - unsigned char fpr[20]; - char *uri; - int i; - - if (argc < 2) - { - fprintf (stderr, "usage: pka mail-addresses\n"); - return 1; - } - argc--; - argv++; - - for (; argc; argc--, argv++) - { - uri = get_pka_info ( *argv, fpr ); - printf ("%s", *argv); - if (uri) - { - putchar (' '); - for (i=0; i < 20; i++) - printf ("%02X", fpr[i]); - if (*uri) - printf (" %s", uri); - xfree (uri); - } - putchar ('\n'); - } - return 0; -} -#endif /* TEST */ - -/* -Local Variables: -compile-command: "cc -DUSE_DNS_PKA -DTEST -I.. -I../include -Wall -g -o pka pka.c -lresolv ../tools/no-libgcrypt.o ../jnlib/libjnlib.a" -End: -*/ diff --git a/common/pka.h b/common/pka.h index 68b4c2ef6..93a4eb3ee 100644 --- a/common/pka.h +++ b/common/pka.h @@ -29,7 +29,7 @@ #ifndef GNUPG_COMMON_PKA_H #define GNUPG_COMMON_PKA_H -char *get_pka_info (const char *address, unsigned char *fpr); +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 new file mode 100644 index 000000000..7c4d7c306 --- /dev/null +++ b/common/t-pka.c @@ -0,0 +1,72 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#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 = "[email protected]"; + 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/configure.ac b/configure.ac index 0d18f1997..34fffb28d 100644 --- a/configure.ac +++ b/configure.ac @@ -920,18 +920,12 @@ AC_ARG_ENABLE(dns-srv, [disable the use of DNS SRV in HKP and HTTP]), use_dns_srv=$enableval,use_dns_srv=yes) -AC_ARG_ENABLE(dns-pka, - AC_HELP_STRING([--disable-dns-pka], - [disable the use of PKA records in DNS]), - use_dns_pka=$enableval,use_dns_pka=yes) - AC_ARG_ENABLE(dns-cert, AC_HELP_STRING([--disable-dns-cert], [disable the use of CERT records in DNS]), use_dns_cert=$enableval,use_dns_cert=yes) -if test x"$use_dns_pka" = xyes || test x"$use_dns_srv" = xyes \ - || test x"$use_dns_cert" = xyes; then +if test x"$use_dns_srv" = xyes || test x"$use_dns_cert" = xyes; then _dns_save_libs=$LIBS LIBS="" # the double underscore thing is a glibc-ism? @@ -988,10 +982,6 @@ if test x"$use_dns_pka" = xyes || test x"$use_dns_srv" = xyes \ AC_DEFINE(USE_DNS_SRV,1,[define to use DNS SRV]) fi - if test x"$use_dns_pka" = xyes ; then - AC_DEFINE(USE_DNS_PKA,1,[define to use our experimental DNS PKA]) - fi - if test x"$use_dns_cert" = xyes ; then AC_DEFINE(USE_DNS_CERT,1,[define to use DNS CERT]) fi @@ -1010,16 +1000,11 @@ if test x"$use_dns_pka" = xyes || test x"$use_dns_srv" = xyes \ AC_DEFINE(USE_DNS_SRV,1) fi - if test x"$use_dns_pka" = xyes ; then - AC_DEFINE(USE_DNS_PKA,1) - fi - if test x"$use_dns_cert" = xyes ; then AC_DEFINE(USE_DNS_CERT,1,[define to use DNS CERT]) fi else use_dns_srv=no - use_dns_pka=no use_dns_cert=no fi fi diff --git a/g10/getkey.c b/g10/getkey.c index 2a2448462..d54bd57ee 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -2971,10 +2971,8 @@ parse_auto_key_locate (char *options) else if (ascii_strcasecmp (tok, "cert") == 0) akl->type = AKL_CERT; #endif -#ifdef USE_DNS_PKA else if (ascii_strcasecmp (tok, "pka") == 0) akl->type = AKL_PKA; -#endif else if ((akl->spec = parse_keyserver_uri (tok, 1))) akl->type = AKL_SPEC; else diff --git a/g10/keyserver.c b/g10/keyserver.c index ffcc1bfe0..477ff17a2 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -1980,7 +1980,7 @@ keyserver_import_pka (ctrl_t ctrl, *fpr = xmalloc (20); *fpr_len = 20; - uri = get_pka_info (name, *fpr); + uri = get_pka_info (name, *fpr, 20); if (uri && *uri) { /* An URI is available. Lookup the key. */ diff --git a/g10/mainproc.c b/g10/mainproc.c index 753fdbedd..0ae916852 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -1498,7 +1498,8 @@ pka_uri_from_sig (PKT_signature *sig) { char *uri; - uri = get_pka_info (sig->pka_info->email, sig->pka_info->fpr); + uri = get_pka_info (sig->pka_info->email, + sig->pka_info->fpr, sizeof sig->pka_info->fpr); if (uri) { sig->pka_info->valid = 1; |