diff options
Diffstat (limited to 'g10')
-rw-r--r-- | g10/Makefile.am | 3 | ||||
-rw-r--r-- | g10/call-dirmngr.c | 235 | ||||
-rw-r--r-- | g10/call-dirmngr.h | 8 | ||||
-rw-r--r-- | g10/gpgv.c | 16 | ||||
-rw-r--r-- | g10/keyserver-internal.h | 4 | ||||
-rw-r--r-- | g10/keyserver.c | 34 | ||||
-rw-r--r-- | g10/mainproc.c | 38 |
7 files changed, 301 insertions, 37 deletions
diff --git a/g10/Makefile.am b/g10/Makefile.am index b66abb84c..ca99314b7 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -141,8 +141,7 @@ gpgv2_SOURCES = gpgv.c \ # here, even that it is not used by gpg. A proper solution would # either to split up libkeybox.a or to use a separate keybox daemon. LDADD = $(needed_libs) ../common/libgpgrl.a \ - $(ZLIBS) $(DNSLIBS) \ - $(LIBINTL) $(CAPLIBS) $(NETLIBS) + $(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS) gpg2_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \ $(KSBA_LIBS) $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \ $(LIBICONV) $(resource_objs) $(extra_sys_libs) diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c index bb571b2e9..e452c971e 100644 --- a/g10/call-dirmngr.c +++ b/g10/call-dirmngr.c @@ -78,6 +78,16 @@ struct ks_put_parm_s }; +/* Parameter structure used with the DNS_CERT command. */ +struct dns_cert_parm_s +{ + estream_t memfp; + unsigned char *fpr; + size_t fprlen; + char *url; +}; + + /* Data used to associate an session with dirmngr contexts. We can't use a simple one to one mapping because we sometimes need two connections to the dirmngr; for example while doing a listing and @@ -957,3 +967,228 @@ gpg_dirmngr_ks_put (ctrl_t ctrl, void *data, size_t datalen, kbnode_t keyblock) close_context (ctrl, ctx); return err; } + + + +/* Data callback for the DNS_CERT command. */ +static gpg_error_t +dns_cert_data_cb (void *opaque, const void *data, size_t datalen) +{ + struct dns_cert_parm_s *parm = opaque; + gpg_error_t err = 0; + size_t nwritten; + + if (!data) + return 0; /* Ignore END commands. */ + if (!parm->memfp) + return 0; /* Data is not required. */ + + if (es_write (parm->memfp, data, datalen, &nwritten)) + err = gpg_error_from_syserror (); + + return err; +} + + +/* Status callback for the DNS_CERT command. */ +static gpg_error_t +dns_cert_status_cb (void *opaque, const char *line) +{ + struct dns_cert_parm_s *parm = opaque; + gpg_error_t err = 0; + const char *s; + size_t nbytes; + + if ((s = has_leading_keyword (line, "FPR"))) + { + char *buf; + + if (!(buf = xtrystrdup (s))) + err = gpg_error_from_syserror (); + else if (parm->fpr) + err = gpg_error (GPG_ERR_DUP_KEY); + else if (!hex2str (buf, buf, strlen (buf)+1, &nbytes)) + err = gpg_error_from_syserror (); + else if (nbytes < 20) + err = gpg_error (GPG_ERR_TOO_SHORT); + else + { + parm->fpr = xtrymalloc (nbytes); + if (!parm->fpr) + err = gpg_error_from_syserror (); + else + memcpy (parm->fpr, buf, (parm->fprlen = nbytes)); + } + xfree (buf); + } + else if ((s = has_leading_keyword (line, "URL")) && *s) + { + if (parm->url) + err = gpg_error (GPG_ERR_DUP_KEY); + else if (!(parm->fpr = xtrymalloc (nbytes))) + err = gpg_error_from_syserror (); + else + memcpy (parm->fpr, line, (parm->fprlen = nbytes)); + } + + return err; +} + +/* Ask the dirmngr for a DNS CERT record. Depending on the found + subtypes different return values are set: + + - For a PGP subtype a new estream with that key will be returned at + R_KEY and the other return parameters are set to NULL/0. + + - For an IPGP subtype the fingerprint is stored as a malloced block + at (R_FPR,R_FPRLEN). If an URL is available it is stored as a + malloced string at R_URL; NULL is stored if there is no URL. + + If CERTTYPE is DNS_CERTTYPE_ANY this function returns the first + CERT record found with a supported type; it is expected that only + one CERT record is used. If CERTTYPE is one of the supported + certtypes, only records with this certtype are considered and the + first one found is returned. All R_* args are optional. */ +gpg_error_t +gpg_dirmngr_dns_cert (ctrl_t ctrl, const char *name, const char *certtype, + estream_t *r_key, + unsigned char **r_fpr, size_t *r_fprlen, + char **r_url) +{ + gpg_error_t err; + assuan_context_t ctx; + struct dns_cert_parm_s parm; + char *line = NULL; + + memset (&parm, 0, sizeof parm); + if (r_key) + *r_key = NULL; + if (r_fpr) + *r_fpr = NULL; + if (r_fprlen) + *r_fprlen = 0; + if (r_url) + *r_url = NULL; + + err = open_context (ctrl, &ctx); + if (err) + return err; + + line = es_bsprintf ("DNS_CERT %s %s", certtype, name); + if (!line) + { + err = gpg_error_from_syserror (); + goto leave; + } + if (strlen (line) + 2 >= ASSUAN_LINELENGTH) + { + err = gpg_error (GPG_ERR_TOO_LARGE); + goto leave; + } + + parm.memfp = es_fopenmem (0, "rwb"); + if (!parm.memfp) + { + err = gpg_error_from_syserror (); + goto leave; + } + err = assuan_transact (ctx, line, dns_cert_data_cb, &parm, + NULL, NULL, dns_cert_status_cb, &parm); + if (err) + goto leave; + + if (r_key) + { + es_rewind (parm.memfp); + *r_key = parm.memfp; + parm.memfp = NULL; + } + + if (r_fpr && parm.fpr) + { + *r_fpr = parm.fpr; + parm.fpr = NULL; + } + if (r_fprlen) + *r_fprlen = parm.fprlen; + + if (r_url && parm.url) + { + *r_url = parm.url; + parm.url = NULL; + } + + leave: + xfree (parm.fpr); + xfree (parm.url); + es_fclose (parm.memfp); + xfree (line); + close_context (ctrl, ctx); + return err; +} + + +/* Ask the dirmngr for PKA info. On success the retrieved fingerprint + is returned in a malloced buffer at R_FPR and its length is stored + at R_FPRLEN. If an URL is available it is stored as a malloced + string at R_URL. On error all return values are set to NULL/0. */ +gpg_error_t +gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid, + unsigned char **r_fpr, size_t *r_fprlen, + char **r_url) +{ + gpg_error_t err; + assuan_context_t ctx; + struct dns_cert_parm_s parm; + char *line = NULL; + + memset (&parm, 0, sizeof parm); + if (r_fpr) + *r_fpr = NULL; + if (r_fprlen) + *r_fprlen = 0; + if (r_url) + *r_url = NULL; + + err = open_context (ctrl, &ctx); + if (err) + return err; + + line = es_bsprintf ("DNS_CERT --pka -- %s", userid); + if (!line) + { + err = gpg_error_from_syserror (); + goto leave; + } + if (strlen (line) + 2 >= ASSUAN_LINELENGTH) + { + err = gpg_error (GPG_ERR_TOO_LARGE); + goto leave; + } + + err = assuan_transact (ctx, line, dns_cert_data_cb, &parm, + NULL, NULL, dns_cert_status_cb, &parm); + if (err) + goto leave; + + if (r_fpr && parm.fpr) + { + *r_fpr = parm.fpr; + parm.fpr = NULL; + } + if (r_fprlen) + *r_fprlen = parm.fprlen; + + if (r_url && parm.url) + { + *r_url = parm.url; + parm.url = NULL; + } + + leave: + xfree (parm.fpr); + xfree (parm.url); + xfree (line); + close_context (ctrl, ctx); + return err; +} diff --git a/g10/call-dirmngr.h b/g10/call-dirmngr.h index bae11238c..b9b8e21a3 100644 --- a/g10/call-dirmngr.h +++ b/g10/call-dirmngr.h @@ -31,6 +31,14 @@ gpg_error_t gpg_dirmngr_ks_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp); gpg_error_t gpg_dirmngr_ks_put (ctrl_t ctrl, void *data, size_t datalen, kbnode_t keyblock); +gpg_error_t gpg_dirmngr_dns_cert (ctrl_t ctrl, + const char *name, const char *certtype, + estream_t *r_key, + unsigned char **r_fpr, size_t *r_fprlen, + char **r_url); +gpg_error_t gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid, + unsigned char **r_fpr, size_t *r_fprlen, + char **r_url); #endif /*GNUPG_G10_CALL_DIRMNGR_H*/ diff --git a/g10/gpgv.c b/g10/gpgv.c index 157fdea45..479bb9599 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -575,3 +575,19 @@ agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno) *r_serialno = NULL; return gpg_error (GPG_ERR_NO_SECKEY); } + +gpg_error_t +gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid, + unsigned char **r_fpr, size_t *r_fprlen, + char **r_url) +{ + (void)ctrl; + (void)userid; + if (r_fpr) + *r_fpr = NULL; + if (r_fprlen) + *r_fprlen = 0; + if (r_url) + *r_url = NULL; + return gpg_error (GPG_ERR_NOT_FOUND); +} diff --git a/g10/keyserver-internal.h b/g10/keyserver-internal.h index a955fc7da..fc1c3435d 100644 --- a/g10/keyserver-internal.h +++ b/g10/keyserver-internal.h @@ -42,8 +42,8 @@ gpg_error_t keyserver_search (ctrl_t ctrl, strlist_t tokens); int keyserver_fetch (ctrl_t ctrl, strlist_t urilist); int keyserver_import_cert (ctrl_t ctrl, const char *name, unsigned char **fpr,size_t *fpr_len); -int keyserver_import_pka (ctrl_t ctrl, - const char *name,unsigned char **fpr,size_t *fpr_len); +gpg_error_t keyserver_import_pka (ctrl_t ctrl, const char *name, + unsigned char **fpr,size_t *fpr_len); int keyserver_import_name (ctrl_t ctrl, const char *name,unsigned char **fpr,size_t *fpr_len, struct keyserver_spec *keyserver); diff --git a/g10/keyserver.c b/g10/keyserver.c index abe4bdebf..40ba49a61 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -41,8 +41,6 @@ #include "trustdb.h" #include "keyserver-internal.h" #include "util.h" -#include "dns-cert.h" -#include "pka.h" #ifdef USE_DNS_SRV #include "srv.h" #endif @@ -1897,7 +1895,7 @@ keyserver_import_cert (ctrl_t ctrl, if(domain) *domain='.'; - err = get_dns_cert (look, DNS_CERTTYPE_ANY, &key, fpr, fpr_len, &url); + err = gpg_dirmngr_dns_cert (ctrl, look, "*", &key, fpr, fpr_len, &url); if (err) ; else if (key) @@ -1957,37 +1955,35 @@ keyserver_import_cert (ctrl_t ctrl, /* Import key pointed to by a PKA record. Return the requested fingerprint in fpr. */ -int -keyserver_import_pka (ctrl_t ctrl, - const char *name,unsigned char **fpr,size_t *fpr_len) +gpg_error_t +keyserver_import_pka (ctrl_t ctrl, const char *name, + unsigned char **fpr, size_t *fpr_len) { - char *uri; - int rc = GPG_ERR_NO_PUBKEY; - - *fpr = xmalloc (20); - *fpr_len = 20; + gpg_error_t err; + char *url; - uri = get_pka_info (name, *fpr, 20); - if (uri && *uri) + err = gpg_dirmngr_get_pka (ctrl, name, fpr, fpr_len, &url); + if (url && *url && fpr && fpr_len) { - /* An URI is available. Lookup the key. */ + /* An URL is available. Lookup the key. */ struct keyserver_spec *spec; - spec = parse_keyserver_uri (uri, 1); + spec = parse_keyserver_uri (url, 1); if (spec) { - rc = keyserver_import_fprint (ctrl, *fpr, 20, spec); + err = keyserver_import_fprint (ctrl, *fpr, *fpr_len, spec); free_keyserver_spec (spec); } } - xfree (uri); + xfree (url); - if (rc) + if (err) { xfree(*fpr); *fpr = NULL; + *fpr_len = 0; } - return rc; + return err; } diff --git a/g10/mainproc.c b/g10/mainproc.c index 0f6ba2b32..e72d07640 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -38,9 +38,8 @@ #include "trustdb.h" #include "keyserver-internal.h" #include "photoid.h" -#include "pka.h" #include "mbox-util.h" - +#include "call-dirmngr.h" /* Put an upper limit on nested packets. The 32 is an arbitrary value, a much lower should actually be sufficient. */ @@ -1487,7 +1486,7 @@ get_pka_address (PKT_signature *sig) be retrieved for the signature we merely return it; if not we go out and try to get that DNS record. */ static const char * -pka_uri_from_sig (PKT_signature *sig) +pka_uri_from_sig (CTX c, PKT_signature *sig) { if (!sig->flags.pka_tried) { @@ -1496,17 +1495,28 @@ pka_uri_from_sig (PKT_signature *sig) sig->pka_info = get_pka_address (sig); if (sig->pka_info) { - char *uri; + char *url; + unsigned char *fpr; + size_t fprlen; - uri = get_pka_info (sig->pka_info->email, - sig->pka_info->fpr, sizeof sig->pka_info->fpr); - if (uri) + if (!gpg_dirmngr_get_pka (c->ctrl, sig->pka_info->email, + &fpr, &fprlen, &url)) { - sig->pka_info->valid = 1; - if (!*uri) - xfree (uri); - else - sig->pka_info->uri = uri; + if (fpr && fprlen == sizeof sig->pka_info->fpr) + { + memcpy (sig->pka_info->fpr, fpr, fprlen); + if (url) + { + sig->pka_info->valid = 1; + if (!*url) + xfree (url); + else + sig->pka_info->uri = url; + url = NULL; + } + } + xfree (fpr); + xfree (url); } } } @@ -1734,7 +1744,7 @@ check_sig_and_print (CTX c, kbnode_t node) && (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE) && (opt.keyserver_options.options & KEYSERVER_HONOR_PKA_RECORD)) { - const char *uri = pka_uri_from_sig (sig); + const char *uri = pka_uri_from_sig (c, sig); if (uri) { @@ -1997,7 +2007,7 @@ check_sig_and_print (CTX c, kbnode_t node) if (!rc) { if ((opt.verify_options & VERIFY_PKA_LOOKUPS)) - pka_uri_from_sig (sig); /* Make sure PKA info is available. */ + pka_uri_from_sig (c, sig); /* Make sure PKA info is available. */ rc = check_signatures_trust (sig); } |