aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/Makefile.am3
-rw-r--r--common/dns-cert.c15
-rw-r--r--common/pka.c341
-rw-r--r--common/pka.h2
-rw-r--r--common/t-pka.c72
-rw-r--r--configure.ac17
-rw-r--r--g10/getkey.c2
-rw-r--r--g10/keyserver.c2
-rw-r--r--g10/mainproc.c3
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;