diff --git a/ChangeLog b/ChangeLog index 657d89a61..9bdbdc0fc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-12-08 Werner Koch + + * configure.ac (USE_DNS_CERT): Support ADNS. + 2009-12-07 Werner Koch * configure.ac: Check for ADNS before checking for the BIND diff --git a/common/ChangeLog b/common/ChangeLog index df058a8fe..f71e0e354 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,7 @@ +2009-12-08 Werner Koch + + * dns-cert.c (get_dns_cert): Add support for ADNS. + 2009-12-08 Marcus Brinkmann * asshelp.c (start_new_gpg_agent): Convert posix FD to assuan FD. diff --git a/common/dns-cert.c b/common/dns-cert.c index ee3b50040..54441d308 100644 --- a/common/dns-cert.c +++ b/common/dns-cert.c @@ -21,13 +21,19 @@ #include #ifdef USE_DNS_CERT # ifdef HAVE_W32_SYSTEM -# include +# include # else -# include -# include -# include +# include +# include +# include +# endif +# include +#endif +#ifdef USE_ADNS +# include +# ifndef HAVE_ADNS_FREE +# define adns_free free # endif -#include #endif #include "util.h" @@ -40,14 +46,106 @@ #define T_CERT 37 #endif +/* ADNS has no support for CERT yes. */ +#define my_adns_r_cert 37 + + /* Returns -1 on error, 0 for no answer, 1 for PGP provided and 2 for - IPGP provided. */ + IPGP provided. Note that this fucntion retruns the first CERT + found with a supported type; it is expected that only one CERT + record is used. */ int -get_dns_cert (const char *name,size_t max_size,IOBUF *iobuf, - unsigned char **fpr,size_t *fpr_len,char **url) +get_dns_cert (const char *name, size_t max_size, IOBUF *iobuf, + unsigned char **fpr, size_t *fpr_len, char **url) { #ifdef USE_DNS_CERT +#ifdef USE_ADNS + adns_state state; + adns_answer *answer = NULL; + int rc; + unsigned int ctype; + int count; + + rc = adns_init (&state, adns_if_noerrprint, NULL); + if (rc) + { + log_error ("error initializing adns: %s\n", strerror (errno)); + return -1; + } + + rc = adns_synchronous (state, name, (adns_r_unknown | my_adns_r_cert), + adns_qf_quoteok_query, &answer); + if (rc) + { + /* log_error ("DNS query failed: %s\n", strerror (errno)); */ + adns_finish (state); + return -1; + } + if (answer->status != adns_s_ok) + { + /* 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 0; + } + + for (rc = 0, count=0; !rc && count < answer->nrrs; count++) + { + int datalen = answer->rrs.byteblock[count].len; + const unsigned char *data = answer->rrs.byteblock[count].data; + + if (datalen < 5) + continue; /* Truncated CERT record - skip. */ + + ctype = ((data[0]<<8)|data[1]); + /* (key tag and algorithm fields are not required.) */ + data += 5; + datalen -= 5; + + if (ctype == 3 && datalen >= 11) + { + /* CERT type is PGP. Gpg checks for a minimum length of 11, + thus we do the same. */ + *iobuf = iobuf_temp_with_content ((char*)data, datalen); + rc = 1; + } + else if (ctype == 6 && datalen && datalen < 1023 + && datalen >= data[0]+1 && fpr && fpr_len && url) + { + /* CERT type is IPGP. We made sure tha the data is + plausible and that the caller requested the + information. */ + *fpr_len = data[0]; + if (*fpr_len) + { + *fpr = xmalloc (*fpr_len); + memcpy (*fpr, data+1, *fpr_len); + } + else + *fpr = NULL; + + if (datalen > *fpr_len + 1) + { + *url = xmalloc (datalen - (*fpr_len+1) + 1); + memcpy (*url, data + (*fpr_len+1), datalen - (*fpr_len+1)); + (*url)[datalen - (*fpr_len+1)] = '\0'; + } + else + *url = NULL; + + rc = 2; + } + } + + adns_free (answer); + adns_finish (state); + return rc; + +#else /*!USE_ADNS*/ + unsigned char *answer; int r,ret=-1; u16 count; @@ -178,8 +276,8 @@ get_dns_cert (const char *name,size_t max_size,IOBUF *iobuf, fail: xfree(answer); - return ret; +#endif /*!USE_ADNS*/ #else /* !USE_DNS_CERT */ return -1; #endif diff --git a/configure.ac b/configure.ac index eb03419ac..f56c154e6 100644 --- a/configure.ac +++ b/configure.ac @@ -831,7 +831,6 @@ if test x"$use_dns_pka" = xyes || test x"$use_dns_srv" = xyes \ else # If we have no resolver library but ADNS (e.g. under W32) enable the # code parts which can be used with ADNS. - use_dns_cert=no if test x"$have_adns" = xyes ; then DNSLIBS="$ADNSLIBS" AC_DEFINE(USE_ADNS,1,[Use ADNS as resolver library.]) @@ -843,9 +842,14 @@ if test x"$use_dns_pka" = xyes || test x"$use_dns_srv" = xyes \ 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/keyserver/gpgkeys_kdns.c b/keyserver/gpgkeys_kdns.c index 5979b0668..b9232c45f 100644 --- a/keyserver/gpgkeys_kdns.c +++ b/keyserver/gpgkeys_kdns.c @@ -66,7 +66,7 @@ static const char *kdns_root; /* The replacement string for the at sign. */ static const char *kdns_at_repl; -/* Flag indicating that a TCP conenction should be used. */ +/* Flag indicating that a TCP connection should be used. */ static int kdns_usevc;