/* dns-cert.c - DNS CERT code * Copyright (C) 2005, 2006 Free Software Foundation, Inc. * * 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 #ifdef USE_DNS_CERT # ifdef HAVE_W32_SYSTEM # include # else # include # include # include # endif #include #endif #include "util.h" #include "iobuf.h" #include "dns-cert.h" /* Not every installation has gotten around to supporting CERTs yet... */ #ifndef T_CERT #define T_CERT 37 #endif /* Returns -1 on error, 0 for no answer, 1 for PGP provided and 2 for IPGP provided. */ int 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 unsigned char *answer; int r,ret=-1; u16 count; if(fpr) *fpr=NULL; if(url) *url=NULL; answer=xmalloc(max_size); r=res_query(name,C_IN,T_CERT,answer,max_size); /* Not too big, not too small, no errors and at least 1 answer. */ if(r>=sizeof(HEADER) && r<=max_size && (((HEADER *)answer)->rcode)==NOERROR && (count=ntohs(((HEADER *)answer)->ancount))) { int rc; unsigned char *pt,*emsg; emsg=&answer[r]; pt=&answer[sizeof(HEADER)]; /* Skip over the query */ rc=dn_skipname(pt,emsg); if(rc==-1) goto fail; pt+=rc+QFIXEDSZ; /* There are several possible response types for a CERT request. We're interested in the PGP (a key) and IPGP (a URI) types. Skip all others. TODO: A key is better than a URI since we've gone through all this bother to fetch it, so favor that if we have both PGP and IPGP? */ while(count-->0 && pt=pt[0]+1 && fpr && fpr_len && url) { /* IPGP type */ *fpr_len=pt[0]; if(*fpr_len) { *fpr=xmalloc(*fpr_len); memcpy(*fpr,&pt[1],*fpr_len); } else *fpr=NULL; if(dlen>*fpr_len+1) { *url=xmalloc(dlen-(*fpr_len+1)+1); memcpy(*url,&pt[*fpr_len+1],dlen-(*fpr_len+1)); (*url)[dlen-(*fpr_len+1)]='\0'; } else *url=NULL; ret=2; break; } /* Neither type matches, so go around to the next answer. */ pt+=dlen; } } fail: xfree(answer); return ret; #else /* !USE_DNS_CERT */ return -1; #endif } /* Test with simon.josefsson.org */ #ifdef TEST int main(int argc,char *argv[]) { unsigned char *fpr; size_t fpr_len; char *url; int rc; IOBUF iobuf; if(argc!=2) { printf("cert-test [name]\n"); return 1; } printf("CERT lookup on %s\n",argv[1]); rc=get_dns_cert (argv[1],16384,&iobuf,&fpr,&fpr_len,&url); if(rc==-1) printf("error\n"); else if(rc==0) printf("no answer\n"); else if(rc==1) { printf("key found: %d bytes\n",(int)iobuf_get_temp_length(iobuf)); iobuf_close(iobuf); } else if(rc==2) { if(fpr) { size_t i; printf("Fingerprint found (%d bytes): ",(int)fpr_len); for(i=0;i