From bb861ac7303cd8f4f054337d7f9997e41df28c17 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 8 Dec 2009 12:20:11 +0000 Subject: Support CERT records via ADNS --- common/ChangeLog | 4 ++ common/dns-cert.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 111 insertions(+), 9 deletions(-) (limited to 'common') 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 -- cgit v1.2.3